Tag Archives: twitter

How to Automate Twitter – continued …

English: Python logo Deutsch: Python Logo

English: Python logo Deutsch: Python Logo (Photo credit: Wikipedia)

Pre-warning – I wrote this pretty late at night for me, and it doesn’t actually work at the moment – consider this an Agile release process …

Ok, so here is version 0.01 of the automated Twitter utility (I will be using it to re-publicise this blog entry, along with a couple of others – so this could either be a brilliant advert or a dire warning!1). I’ve changed the frequency criteria somewhat from the original, there are now 24 re-tweets with an hours increase in delay between each ( e.g. tweet, 1 hour, 2 hours, 3 hours up to and including 24 hours – overall this spreads out 24 tweets over 11 days or so ) – I’ll give that a go, and maybe experiment from there. I’ve also included a schedule file reference into the configuration file so that it is easier to change should it be neccesary. The overall lack of semi-colons and brackets has given me a nervous twitch, but other than that, given that I’m pretty new to Python, that was – all in all – not a terrible experience !

#!/usr/bin/env python

##########################
# Python Auto Re-Tweeter #
# (C) Simon Biles 2012   #
# http://www.biles.net   #
##########################
# Version 0.01 -         #
# A first stab at it !   #
##########################

# All those tasty Python imports

import argparse
import datetime
import struct
import sys
import tweepy
from ConfigParser import SafeConfigParser

# Get the command line arguments

parser = argparse.ArgumentParser(description='Regular Tweet Generator.')
parser.add_argument('-s','--schedule', action='store_true', help='Schedule a Tweet for the next 7 days')
parser.add_argument('-r', '--run', action='store_true', help='Run the schedule')
parser.add_argument('-u','--update', action='store_true', help='Update Status Tweet immediately')
parser.add_argument('tweet', nargs='?')
args = parser.parse_args();

# Global variable

time_fmt = "%Y-%m-%d %H:%M"

# Get the config file data

parser = SafeConfigParser()
parser.read('twitter.conf')
CONSUMER_KEY = parser.get('consumer_keys','CONSUMER_KEY')
CONSUMER_SECRET = parser.get('consumer_keys','CONSUMER_SECRET')
ACCESS_KEY = parser.get('access_keys','ACCESS_KEY')
ACCESS_SECRET = parser.get('access_keys','ACCESS_SECRET')
FILE_NAME = parser.get('file_name', 'SCHEDULE_FILE')

# Main body

# Quick Command Line Status Update

if args.run == False and args.schedule == False and args.update == True:
   auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
   auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
   api = tweepy.API(auth)
   api.update_status(sys.argv[1])
   sys.exit()

# Schedule a Tweet by adding it to the schedule file

elif args.run == False and args.schedule == True and args.update == False:
   file_obj = open(FILE_NAME, 'a')
   current = datetime.datetime.now()
   nexttweet = current;
   count = 0
   while (count < 24):
      diff = datetime.timedelta(hours=count)
      nexttweet = nexttweet + diff
      tweettime = nexttweet.strftime(time_fmt) + " " + args.tweet +"\n"
      file_obj.write(tweettime)
      count = count + 1
   file_obj.close 
   sys.exit()# Parse the schedule file and see if anything should have happend within 5 minutes of now.elif args.run == True and args.schedule == False and args.update == False:
   file_obj = open(FILE_NAME, 'r')
   auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
   auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
   api = tweepy.API(auth)
   current = datetime.datetime.now()
   baseformat = "16s 1x"
   for line in file_obj:
      line = line.rstrip('\n')
      numremain = len(line) - struct.calcsize(baseformat)
      lformat = "%s %ds" % (baseformat, numremain)
      tweettime, tweet = struct.unpack(lformat, line)
      linetime = datetime.datetime.strptime(tweettime, time_fmt)
      delta = linetime - current
      if delta <= datetime.timedelta(minutes=5) and delta >= datetime.timedelta(minutes=-5):
         api.update_status(tweet)
   file_obj.close
   sys.exit()

I think that it works ok, I’m going to carry out testing in live – like all good practice guides suggest you shouldn’t ! I’m going to set it to run with the -r command line switch from cron every five minutes.

There are one or two features that I think that I should look into in the near-ish future:

  • Cleaning up the schedule file – obviously it is only going to get longer and longer and thus the program will consume more and more resources as it tries to parse it.
  • I’d like to automate the script so that it monitors my Twitter account for updates from WordPress, and then adds those to the schedule immediately – I’m lazy you see …
  • I’m sure that there are a few better ways of doing things in there, and also there could be a little more in the way of commentary and instruction ( there are also, frankly, one or two bits that work, but that I don’t understand how ! )

Ah well, onward and upward eh 😉


1. Ok, it’s a dire warning … It worked on the command line, honest !

UPDATE: If you decide to go live and test there, you then spend time hurriedly chasing down the bugs in your code which you just posted on your blog so as not to look like a complete berk … You have been warned !

UPDATE 2: Hmmm … Not _actually_ working, that’s a bit lousy … Ah, wait. I think I know what the problem is ! You need to specify the full path to the file in the config as cron doesn’t run in the same path ! Right take 3 !

UPDATE 3: Ok, that didn’t work … Back to the drawing board. Unfortunately I don’t have time now 😦 so I’ll have to come back in another post later … Arrrrggghhh !

Tagged , , , , , , , , ,

How to Automate Twitter – a bit at least !

Perl

Perl (Photo credit: Wikipedia)

I’ve been trying to push up the readership of the blog here ( and get some people to stick around a bit, subscribe, follow on twitter etc. )  I’m not a Facebooker – I do have an account ( or two … ) but they contain nothing much of interest, they were created in order to investigate how FB worked, rather than anything else, so I’m not exactly the stereotypical user ! I make use of LinkedIn and Twitter as my online “social” tools and I’ve not graduated beyond that. The trouble is, I believe, in the transient nature of Twitter – I Tweet and it disappears off the bottom of the screen in seconds as other’s posts come in and push it down. I’ve watched for a while, and it seems that the “successful” Tweeters post their links frequently – keeping them in view for a longer period of time.

Now, I have to admit that I am lazy, but also geeky – I want to post a tweet advertising the blog frequently, but without user interaction. I’m sure that people will pop-up and tell me of things that automagically do this for me – HootSuite springs to mind – but having used it, it has already upset me with it’s scheduling system – the CSV upload is a pain, and, as of yet, I’ve not managed a single one without an error. Sooo, as I spent a while ago messing around with Twitter and Perl, I thought that the easiest way forward might just be to write my own.

For want of a better methodology, as I intend to post once a week, I want each entry alerted on immediately, and then in increasing intervals until the next post is due out ( 1 week hence ). I don’t want mid-term posts to reset the last weeks worth, but if it is relevant ( like I hope all posts are !) then I do want to publicise it for a full week as well. I’ve tried a couple of exponential increases, (2 * last period, 1.5 * last period ), but to be honest as I’m sure you can imagine, it gets up to over a day fairly quickly … (Google “exponential” if you want to know more !)  So I’m going to say day one is once every two hours, day two is once every three hours, day three once every four hours, day four is four times in the day, day five is three times a day, day six is twice, and just the once on the seventh day – heck, if God can take a rest, so can our program ! That gives us a total of 36 Tweets, weighted towards the start whilst the post is fresh and tailing off as the new post comes along.

As always stated with my programming posts, I’m not a programmer, any similarity to programmers living or dead is entirely coincidental. I like programming in Perl, because, not only is “there more than one way to do it”, I can usually figure out at least one of those particular permutations – elegant as my solution may not be … [ if you want to see elegant programming – and the output of the man that I go to when I get stuck – have a look over here. Shamefully he wastes his time in the world of Microsoft, but we forgive him a lot 😉 ]

It turns out, much to my annoyance that the authentication methods that I was using in the “Hacking around with Twitter” is no longer valid. It seems that I now need to use OAuth1 … However, after several hours of buggering around with it I failed completely to get it to work. So back to the drawing board there …

Python anybody ?

English: Python logo Deutsch: Python Logo

English: Python logo Deutsch: Python Logo (Photo credit: Wikipedia)

I’ve been meaning to get cracking with Python for some time. I was a die hard Perl fan until the day I saw the graphs that came from matplotlib – I was taken by the quality and professionalism of them, and I immediately spent far more money than can be considered sensible on all sorts of Python books so that I too, could make maths and art become one and the same thing. It seems though that I have the same level of programming ability as a garden slug when it comes to moving languages, and the same sort of speed of movement. It took me three years (ish) at university to learn C [ and ML and Prolog – but let’s be honest, neither of those actually count as programming languages ] and it’s taken me countless years since to learn to threaten, coerce and cajole Perl to do my bidding at least 50% of the time.

This, then, is my forced introduction to Python – my baptism of fire ( although God only knows why, if I can’t do it in Perl I stand the least bit of chance in Python ! ). And, not only that, I’m going to push it out here for your ridicule and derision.

Another day, I’d like to walk through the Rackspace cloud with you, but that’s for another day – let us just say, that I quickly threw up an Fedora 15 (Lovelock) instance to play with, and was deeply relieved that Python appears to be a standard part of the distribution. For reference my development environment also consists of Komodo Edit, which is excellent, with supported syntax highlighting for both Perl and Python ( and HTML and C and C++ and … ) also, when correctly configured, is quite happy using scp to remotely edit files and browse remote directories.

I understand that the Python equivalent of CPAN is PyPI – the Python Package Index – and, after installing the package, I’ve used that to install the Tweepy library. I’m not going to repeat the guidance on creating a new application in either (both!) of the blog links below – what I will say though is that you should remember to set your application settings to Read and Write – otherwise it won’t work 😉2

I’ve split the examples out so that there is a config file that holds the various keys. It’s format is as follows:

[consumer_keys]
CONSUMER_KEY = consumer_key_here
CONSUMER_SECRET = consumer_secret_here
[access_keys]
ACCESS_KEY = access_key_here
ACCESS_SECRET = access_secret_here

Obviously insert your own, hard earned keys in here – no inverted commas or anything they get parsed in a minute with ConfigParser. [ Basically, I couldn’t go through the rest of this worrying about accidentally publishing my keys every five minutes. ]. I used the script provided in the example to do this, although it seems that you can generate these keys for your own Twitter account in the developer section of the site without going through the pain or the learning experience.

I’m getting worried how long this post is getting – especially after a discussion with a young man the other day who said that his dissertation was 5000 words only and I’ve written a 5th of that ! – so below is the remainder of the sample code for a command line client, this takes text after the command ( contained in ‘ ‘ ) and updates your status with it ( e.g. ./twitter.py ‘It lives!’ ):

#!/usr/bin/env python

import sys
import tweepy
from ConfigParser import SafeConfigParser

parser = SafeConfigParser()
parser.read('twitter.conf')

CONSUMER_KEY = parser.get('consumer_keys','CONSUMER_KEY')
CONSUMER_SECRET = parser.get('consumer_keys','CONSUMER_SECRET')
ACCESS_KEY = parser.get('access_keys','ACCESS_KEY')
ACCESS_SECRET = parser.get('access_keys','ACCESS_SECRET')

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
api = tweepy.API(auth)api.update_status(sys.argv[1])

I’ll write a second post within the next week to update the remainder with a full program to automate the remainder of the posting process – I want to get it running asap to be honest, as I think I’m missing out !


1. With thanks to David Moreno’s blog post on the issue as my starting point on OAuth for Perl, and perhaps the first and last bit of it that I understood ! And Jeff Miller’s blog post for the Python equivalent.
2. Which may well be why I couldn’t get the darn Perl version to work, I realise now. However, a kick in the pants, is a kick in the pants for whatever reason it comes …

Tagged , , , , , , , , , , ,

DMU and Documents …

I’m embarrassed to say that I’ve let my blogging slip again – I’d like to plead busy-ness, and it isn’t as if my Twitter hasn’t suffered too ! I think I’ve managed one Tweet this year so far …

In any case, it isn’t like I’ve got much more time now – I’m currently in Leicester at DeMontfort University sitting in the brand new PostGrad Forensics Lab on the “Binary Analysis of Microsoft Office Documents” course. I’ve jumped ship from Cranfield & Shrivenham to follow Professors Tony Sammes and Brian Jenkinson to their new home in the Cyber Security department of DMU*, and I must admit that I have only one regret and that is that Leicester is so much further from home ! Other than that, the course ( so far ! This is day 2 … ) is excellent – the facilities here are far superior to those at Cranfield – much has been invested in the brand new lab – a 15 seat (on a quick count – looks like it can support 3 more) there are some of the snazziest whiteboards that I’ve ever seen (frosted glass none-the-less) and some excellent HD projectors. The smell of various solvents – carpet & paint I think – still are lingering a little, but the AC is gradually filtering it out as the week goes on.

Regarding the course, I won’t divulge content as it is a commercial advantage held by DMU now – I don’t think that you can get this course anywhere else – but needless to say, when it’s being presented by Tony and Brian, you can imagine that not only is it as full of content as you can cram into a day, but it is also seriously stretching all of us here I think – given that 50% of the students are doing their PhD here, I think that gives you some idea of the level that we’re talking about here.

There are several hotels listed by the University, but the closest is the Holiday Inn at St.Nicholas Circle – it’s perfectly acceptable, food is pretty good and the staff are attentive in the restaurant. The Gym, to be fair, is laughable, but lets face it, a majority of Forensic Examiners are known for their athletic ability 😉 It is only a short walk from the Gateway Building where the lab is – and thus far I’ve been blessed with good weather …

Catering on the course is a matter of going to get it yourself – this isn’t a hardship, as the Student Center next door has a number of options for food – including a Starbucks (either rejoice or groan as you personally desire – for me, it beats Nescafe, so I won’t complain !) There is a cash machine, small supermarket etc. much the same range as I recall from my experiences at Edinburgh and Imperial … There seems to be an absence of card taking at the till points – I guess students only operate in cash – so just be prepared. Oh, and two other points – 1) Avoid going to lunch at 1pm, the mass of the student population arrives at this point and 2) there appears to be a constant charity fundraising presence outside – as one of my post-grad colleagues pointed out – this allows the undergrads to feel productive without actually having to do any work 😛 ( Be careful when purchasing cakes/biscuits from the stalls – I’m not sure that student kitchens are best designed for mass catering, and, although the flavour was lovely – the image of Brian having to break his biscuit by repeatedly smashing it against the table in order to eat it will remain with me for a long time ! )

I’ll update this a little later in the week when a bit more course has been covered … But, from first impressions, I’m really rating the move from Cranfield/Shrivenham as “a good thing”…

For more information on De Montfort University courses – both Undergraduate and Postgraduate Forensics & Information Security go to HERE.

* Ok people, let’s be brutally honest here – there isn’t really a course left at Cranfield after Tony and Brian left – so I can’t say that there was much point in _not_ following them …

Tagged , , , ,

Hacking around with Twitter (Part 3 !) …

Well that took a little while, but it is now all done 🙂

Et voila :

#!/usr/bin/perl -w
#use strict;

use Getopt::Long;
use Storable;
use Net::Twitter::Lite;
use Crypt::OpenSSL::Random;
use Crypt::OpenSSL::RSA;
use MIME::Base64;

#----------------------------------------------#
#                  This is :                   #
 $clientname = "twitter crypt";       #
#                  Version :                   #
 $clientver = "0.1";            #
#----------------------------------------------#
#            By : Simon Biles                  #
$clienturl="http://computersecurityonline.com";#
#----------------------------------------------#

# Saved Public Keys File
$Public_Keys_File = "twc_public_keys";

GetOptions("genkey=s" => \$genkey,
 "publishkey=s" => \$publishkey,
 "getkeys" => \$getkeys,
 "showkeys" => \$showkeys,
 "encrypt=s" => \$encrypt,
 "getmessages=s" => \$getmessages,
 "user=s" => \$user,
 "pass=s" => \$password );

if (defined $genkey){
 $good_entropy = "10010101001010101";

 Crypt::OpenSSL::Random::random_seed($good_entropy);
 Crypt::OpenSSL::RSA->import_random_seed();

 $rsa = Crypt::OpenSSL::RSA->generate_key(640);

 $private = $rsa->get_private_key_string();
 $public = $rsa->get_public_key_string();

 print "\nprivate key is:\n $private\n";
 print "\npublic key (in PKCS1 format) is:\n $public\n"; 

 open(KEYFILE, "> $genkey") or die $!;
 print KEYFILE "$private\n$public";
 close KEYFILE;

 print "\nKeys written to file $genkey ...\n\n";

 exit 0;
}

if (defined $publishkey && defined $user && defined $password){

 my $nt = Net::Twitter::Lite->new(
 username => $user,
 password => $password,
 clientname => $clientname,
 clientver => $clientver,
 clienturl => $clienturl
 );

 open (KEYFILE, "< $publishkey");
 $flag = 0;
 $public_key = "";
 while (<KEYFILE>){
 if ($_ =~ /-----END RSA PUBLIC KEY-----/) { last; };
 if ($flag == 1) { $public_key = $public_key.$_; };
 if ($_ =~ /-----BEGIN RSA PUBLIC KEY-----/) { $flag = 1; };
 }

 $public_key = "twc-public -".$public_key;

 $key_length = length $public_key;

 print "Length: $key_length \n$public_key";

 if($key_length > 140){
 print "\nFor some reason we've over shot our 140 chars for Twitter, complain ...\n";
 exit 0;
 }

 my $result = eval { $nt->update($public_key) };

 exit 0;
}

if($getkeys && defined $user && defined $password){

if(-e $Public_Keys_File){
 %keys_hash = %{retrieve($Public_Keys_File)};
} else {
 %keys_hash = ();
}

 my $nt = Net::Twitter::Lite->new(
 username => $user,
 password => $password,
 clientname => $clientname,
 clientver => $clientver,
 clienturl => $clienturl
 );

 eval {
 my $statuses = $nt->friends_timeline();
 for my $status ( @$statuses ) {
 if ($status->{text} =~ /twc-public -/){
 ($public_key_string = $status->{text}) =~ s/twc-public -//;
 $keys_hash{ $status->{user}{screen_name} } = $public_key_string;
 }
 }
 };
 warn "$@\n" if $@;

store(\%keys_hash, $Public_Keys_File) or die "\nCan't save public keys to $Public_Keys_File.\n\n";

 exit 0;
}

if($showkeys){

if(-e $Public_Keys_File){
 %keys_hash = %{retrieve($Public_Keys_File)};
 while (($key, $value) = each(%keys_hash)){
 print "$key - $value\n";
 }

} else {

 print "\n\n Public Keys file $Public_Keys_File does not exist, create it using the --getkeys option.";

}

 exit 0;
}

if(defined $encrypt && defined $user && defined $password){

if(-e $Public_Keys_File){
 %keys_hash = %{retrieve($Public_Keys_File)};

 $encryption_key = "-----BEGIN RSA PUBLIC KEY-----\n"."$keys_hash{$encrypt}\n"."-----END RSA PUBLIC KEY-----\n";

 print "$encryption_key";

 $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($encryption_key);
 print "                                           |------------------------------------|\n";
 print "Enter your message : (between the lines !) ";
 $plaintext = <STDIN>;    

 if ((length $plaintext) > 38){
 print "Message too long I'm afraid, I did say to stay between the lines ...\n";
 exit 0;
 }

 $ciphertext = $rsa_pub->encrypt($plaintext);

 $encoded_ciphertext = "twc-msg-$encrypt-".encode_base64($ciphertext);
 $encoded_length = length $encoded_ciphertext;

 if ($encoded_length > 140){
 print "Uh-oh, we've had an over Twitter length moment there !\n";
 exit 0;
 }

 my $nt = Net::Twitter::Lite->new(
 username => $user,
 password => $password,
 clientname => $clientname,
 clientver => $clientver,
 clienturl => $clienturl
 );

 my $result = eval { $nt->update($encoded_ciphertext) };

} else {
 print "\n\n Public Keys file $Public_Keys_File does not exist, so there is no key for $encrypt create it using the --getkeys option.";
 exit 0;
}

 exit 0;
}

if(defined $getmessages && defined $user && defined $password){

$private_key = "";

 if (-e $getmessages){
 open (FILEHANDLE, "< $getmessages");
 while(<FILEHANDLE>){
 if ($_ =~ /-----BEGIN RSA PRIVATE KEY-----/){
 $flag = 1;
 }
 if ($flag == 1){
 $private_key = "$private_key"."$_";
 }
 if($_ =~ /-----END RSA PRIVATE KEY-----/){ last; }
 }

 $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key);

 my $nt = Net::Twitter::Lite->new(
 username => $user,
 password => $password,
 clientname => $clientname,
 clientver => $clientver,
 clienturl => $clienturl
 );

 eval {
 my $statuses = $nt->friends_timeline();
 for my $status ( @$statuses ) {
 if ($status->{text} =~ /twc-msg-$user-/){
 $from = $status->{user}{screen_name};
 ($encoded_ciphertext = $status->{text}) =~ s/twc-msg-$user-//;
 $ciphertext = decode_base64($encoded_ciphertext);
 $decrypted = $rsa_priv->decrypt($ciphertext);
 print "Message from $from : $decrypted\n";
 }
 }
 };
 warn "$@\n" if $@;

 exit 0;
 } else {
 print "That key file doesn't appear to exist ...\n";
 exit 0;
 }

 exit 0;
}

#Useage information ... should get here if all else fails !

print "\nSorry the correct useage of twcrypt.pl is :\n\n";
print "twcrypt.pl --genkey keyfile\n\t- generate a key file of name keyfile.\n\n";
print "twcrypt.pl --publishkey keyfile --user username --pass password\n\t- publish the keyfile to twitter for specified account.\n\n";
print "twcrypt.pl --getkeys --user username --pass password\n\t- collect keys published by people you are following.\n\n";
print "twcrypt.pl --showkeys\n\t- show cached public keys.\n\n";
print "twcrypt.pl --encrypt to --user username --pass password\n\t- encrypt a message to a given user.\n\n";
print "twcrypt.pl --getmessages --user username --pass password\n\t- get messages sent to you.\n\n\n";
print "I do realise this isn't the best interface, but hell, live with it ...\n\n";

exit 0;

It works too ! Creating, uploading, encrypting and decrypting through Twitter – Twitter PKI – you saw it here first 😛

I only made one small modification to the planed implementation, and that was to include the name of the recipient – I found that the attempt to decrypt a message with the wrong private key for the encryption caused a crash out, so I though that it would be best to keep it to only decrypting what it is supposed to.

All comments and critique of my code welcome … Please remember though that it’s only a proof of concept – I would be interested in any major flaws though … ( A low key length isn’t a flaw, it’s a practicality by the way – 640 bits should keep most people at bay for a fairly reasonable amount of time 🙂 and is all I could fit into Twitter. ) I hope that the code is self explanatory, if you do have any questions, please drop me a line at si at thinking-security.com

I’m going to go and have a break from the computer now … I might fiddle with this some more later to make it a little more useable, maybe a GUI or iPhone version 😉

Tagged , , ,

Hacking around with Twitter … ( Part 2 ! )

Cryptographically secure pseudorandom number g...

 (Photo credit: Wikipedia)

Well, I’m into day two of this project – well into the code now, and it’s comming on ok …

Phase 4(a) : Get Net::Twitter::Lite to connect to, pick up and update an account. This is pretty well documented in the examples on CPAN, although I’ve pared it right down to the minimum in just to get the post, as the date was throwing up an error, as it isn’t important to the proof of concept at this point ( might be a nicety later on … ) so the code stands like this just now …

#!/usr/bin/perl -w
#use strict;

use Net::Twitter::Lite;

#----------------------------------------------#
#                  This is :                   #
 $clientname = "twitter crypt";       #
#                  Version :                   #
 $clientver = "0.1";            #
#----------------------------------------------#
#            By : Simon Biles                  #
$clienturl="http://computersecurityonline.com";#
#----------------------------------------------#

$user="twcrypt";
$password="*********";

 my $nt = Net::Twitter::Lite->new(
 username => $user,
 password => $password,
 clientname => $clientname,
 clientver => $clientver,
 clienturl => $clienturl
 );

 my $result = eval { $nt->update('Hello, world!') };

 eval {
 my $statuses = $nt->friends_timeline();
 for my $status ( @$statuses ) {
 print "<$status->{user}{screen_name}> $status->{text}\n";
 }
 };
 warn "$@\n" if $@;

In theory the $clientname and $clientver should change the “via” entry, however this doesn’t seem to be the case as it appears to remain as “via Perl Net::Twitter” in TweetDeck.

This gives out the result of :

MacBook:TWCrypt si$ ./twcrypt.pl
 Hullooo ?
 twcrypt_a test
 Hello, world!

Which are either from <twcrypt> the result of the update or are pulling from the following list posts. So far so good !

Phase 4(b) : Right, now for RSA Encryption … If you aren’t familiar with RSA ( and I only vaugely remember the maths from University … ) it is a public key crypto system developed originally at GCHQ, although the offical secrets act meant that Ron Rivest, Adi Shamir, and Leonard Adleman got there independently. I’m _not_ going to go through how it works, mostly ‘cos I’d confuse the matter more, but the Wikipedia Article is pretty good ! Ignore the maths and work through the example to really get how it works 🙂

The example code for Crypt::OpenSSL::RSA isn’t quite so good, there are some typos which have left me stumped for ages … But I got there in the end, and in conjunction with MIME::Base64 have a way of encoding and decoding the strings into something that Twitter will accept. After playing around with key lengths, I’ve gone with 640bits, as this gives a nice ciphertext size of 110 chars and accomodates an encrypted message of upto 38 chars – not exactly War and Peace – I may have to implement that multi-part message sooner rather than later ! 640 bits also gives an RSA encoded key of 122 chars, so we are still comfortably within the 140 char Twitter limit.

#!/usr/bin/perl -w
#use strict;

use Crypt::OpenSSL::Random;
use Crypt::OpenSSL::RSA;
use MIME::Base64;

$plaintext = "12345678901234567890123456789012345678";
$good_entropy = "10010101001010101";

Crypt::OpenSSL::Random::random_seed($good_entropy);
Crypt::OpenSSL::RSA->import_random_seed();$rsa = Crypt::OpenSSL::RSA->generate_key(640);print "private key is:\n", $rsa->get_private_key_string();
print "public key (in PKCS1 format) is:\n", $rsa->get_public_key_string();print "Plaintext = $plaintext\n";
$ciphertext = $rsa->encrypt($plaintext);
print "Encrypted = -!-$ciphertext-!-\n";
$encoded = encode_base64($ciphertext);
$encoded_length = length $encoded;
print "Encoded = $encoded Length = $encoded_length\n";
$decoded = decode_base64($encoded);
print "Decoded = $decoded\n";
$decrypted = $rsa->decrypt($decoded);
print "Decrypted = $decrypted\n";

This gives us an output of :

MackBook:TWCrypt si$ ./twcrypt.pl
private key is:
-----BEGIN RSA PRIVATE KEY-----
MIIBgwIBAAJRAO2VqyVoQFyJkddP+zPzUuoyfDZVaPgn8LxHKFNETwVKdcAOfvm4
koOBcMcGGgwhaFQjEeg5JpNXBvXg67CbWvGpSLpCxonhFdoJprFAC/GBAgMBAAEC
UQCF0hGuZkQqW0qMTn6dymZfh8QzDnSrokOUqTfrfsRLpJ8iaIfYvL+4wPBb0+9z
1DALyIk9SX+MVTwdE7zanrHAxZVOb/zWVioVca0ih3M4yQIpAPi5mTO0lVU4mSw5
acNoPJhkJp901OYgCXVK75MiKJSb+31TmjSoSo8CKQD0iKdHs1ieaoMMx/K91Zmi
dnb80l7aRkU04OZ1ed201OMyP489D0rvAikA+JxzkOYo+iT3nefJWqO/Jce9f1dF
UrylF5OOgm/7RgffyfadxZKN6wIoRczYCwRrkFSQ8c4FQSC+iPxNvJ8ECkQyrwRf
ZDsUCPEXpRk1dtVtqwIobkZm67KhVm5Hp4NRhWIiFODNuzcfwZfakM8Fhvk9dBtv
1GAKqXOeEQ==
-----END RSA PRIVATE KEY-----
public key (in PKCS1 format) is:
-----BEGIN RSA PUBLIC KEY-----
MFgCUQDtlaslaEBciZHXT/sz81LqMnw2VWj4J/C8RyhTRE8FSnXADn75uJKDgXDH
BhoMIWhUIxHoOSaTVwb14Ouwm1rxqUi6QsaJ4RXaCaaxQAvxgQIDAQAB
-----END RSA PUBLIC KEY-----
Plaintext = 12345678901234567890123456789012345678
Encrypted = -!-g$S9?+?????<}&3~?"?q?    ?=???):??R'?+?/?*3?:??x:??p{?!?o??-??m??ʣ??N?<ɍI?q-!-
Encoded = ZyRTOa8rH531r56PPH99JjN+ryKEcYoJhD2WgqUpOtjIUieLFCuqL5ccKjPuOokT9ng6/NBwe5wh
HOtvkfct4cxtl8LKo4HFTos8yY1J+3E=
 Length = 110
Decoded = g$S9?+?????<}&3~?"?q?    ?=???):??R'?+?/?*3?:??x:??p{?!?o??-??m??ʣ??N?<ɍI?q
Decrypted = 12345678901234567890123456789012345678

So that all appears to be working ok …

Phase 4(c): Stich the two things together into a useable program ! This is only a proof of concept, so I’m going to just write a simple command line utility with a few switches to show the point, the plan ( at the moment ) is to end up with something like this :

twcrypt [--genkey keyfile] [--publishkey keyfile] [--getkeys] [--showkeys] [--encrypt to] [--getmessages keyfile] [--user user] [--pass password]

I hope that is quite self explanitory, but read on anyhoo and you’ll get the drift I’m sure …

I got somewhat distracted last night by a terrible film rental (“Thick as Thieves”, Morgan Freeman and Antonio Banderas – don’t bother, it’s not worth it … ) so I’ve not finished this off yet – I thought that I’d post this much and then the final part soon.

Tagged , , , , , ,

Hacking around with Twitter …

Image representing Twitter as depicted in Crun...

Image via CrunchBase

Twitter is an interesting beast … I’m still not too sure if I really see that there is any real benefit from it – I do find it fun though 🙂 Anyhoo, it occurred to me as I was driving home tonight, stuck in the pouring rain, in Oxford traffic, that Twitter, like all of these social networking sites, is a great way to send coded messages. ( Watch my hit count rise drastically as the NSA and GCHQ hammer me 😉 ) There are enough tweets, and they are random enough to drown out pretty much any useful data, but even so, I’d be reluctant as a spy or other to use twitter either in code or directly to communicate with my handlers / followers … It’s a bit too obvious – this led me to think of encryption, and rather conveniently, Twitter itself sets the key size ! Allowing for a few control characters to identify the different types of message, I think that it is possible to implement a neat little public key exchange / encryption setup using Twitter & using Perl, a few CPAN libraries, and this blog, I’m going to set out to do it as a proof of concept over the next few days …

Phase 1 : Completed before I started typing this up – get myself a few extra twitter accounts to play with TweetDeck graciously supports multiple accounts so I can monitor the Perl back processes, so I now have twcrypt, twcrypt_a and twcrypt_b to play with …

Phase 2: Raid CPAN for someone else’s hard work 🙂 Net::Twitter::Lite by Marc Mims and Crypt::OpenSSL::RSA by Ian Robertson ( after several false starts with other RSA implementations and much fun with Math::Pari. ). So that I stand some chance of getting _some_ sleep before morning ! ( If you are on MacOS X, as I am, running cpan sudo aids in the installation somewhat …  )

Phase 2(a): Install Komodo Edit on new laptop, because I’ve not done it yet … Great Perl editor, and free !

Phase 3: Quick planning stage … 140 chars – 128 char for the key leaves … drum roll … 12 for signals soooo …

01 02 03 04 05 06 07 08 09 10 11 12t  w  c                          -  = type marker ( note the - at char 12 )
t  w  c  -  p  u  b  l  i  c     -  = public key distro indicator
t  w  c  -  m  s  g              -  = message indicator ( thinking about allowing multipart messages later )

That’s about it for now, either I’m too tired, too stupid or there just plain aren’t any more required at this time ( could abbreviate I guess and have a stronger key ? ) At the moment, I think that the two communicating parties are going to have to be followers, with only 12 chars to spare there’s not enough room to use @names …

Quick Aside : This isn’t a 128 bit key, this is a 128 byte key or 8 times that e.g. 1024 bit – this is considered pretty much the minimum standard in the world of encryption with 2048 and larger keys being in common, difficult to break, use. You should bear in mind though that a 1024 bit key still supplies a fair standard of encryption. Having said all of this, OpenSSL is being a bugger for actually generating a key that _is_ 128 bytes long, if I generate a 1024bit key, I seem to end up with a 217 byte public section when all is said and done … More investigation tomorrow !
 
With thanks to ...

With thanks to xkcd

Phase 4: Start writing program … in the morning 🙂

Tagged , , , , , ,