Meet @cryptofax2tweet, a new
Twitter account I run. So, what is so special about this account? As the name
suggests, it can be used to tweet by sending an encrypted QR code using a fax,
for example when your government decides to turn off the internet. In case you
are not interested in the technical details on how it works and just want to
use it, you can download the cryptofax.pdf
file and open it in Adobe Reader. A one page
user’s guide is also available.
So, how does this work? Recent PDF versions support the XML Forms Architecture (XFA),
which I’ve been playing with lately. It includes all kind of funny things, such as its
own language (because having both Javascript and Flash in Reader is not enough, apparently),
FormCalc. It is apparently not more useful than Javascript except if you want to
generate arbitrary HTTP requests.
But I am digressing. One of the more interesting features of XFA is the possibility
to create all kinds of barcodes, both one- and two-dimensional. The list of different
types you can create in the specification is about five pages long(!). Also, the
specification claims that the content of the barcode can be encrypted before creating
it using an RC4/RSA hybrid encryption.
I had recently read about Google’s @speak2tweet
account and liked the idea but not the Medienbruch — the change from one medium (voice) to another
(text). So I thought about implementing something using XFA which would allow people
to send tweets via fax.
One obstacle on the way was finding out that Adobe does not want you to create
dynamic 2D barcodes if you do not have the license for it.
Unluckily, if you do not know this and modify the rawValue attribute of the barcode
field after the form has rendered, you just get to see a grey block instead of the
barcode and keep wondering whether Adobe just broke the functionality. Also, debugging
Javascript code if you only have Adobe Reader is less funny than you think. Once
I figured that out, I realised that you can ask for the dynamic information in the
initialize event handler using app.response() and create the barcode at that point (not sure
whether Adobe would consider this a bug or a feature).
After that was solved, I looked into encrypting the content of the tweet. Note that
the encryption just helps against an attacker who only monitors the phone lines
and not the @cryptofax2tweet account. Still, it might help people who have printed
out the fax and it gets intercepted before it has been faxed. Unluckily, it looks
like this particular functionality from the specification has not been implemented
in Reader (the fact that the LiveCycle® Designer ES Scripting Reference does not talk about it at all points in this direction, too).
Luckily, there was no need to implement the cryptography myself, as there is
already a pretty nice BSD-licensed RSA implementation for Javascript. A few patches later to fix some Reader-specific oddities, I was able to RSA-encrypt a tweet.
As a tweet can only be 140 characters (thus at most 560 bytes in UTF-8), I just used
a 4096 bit RSA key (not for security, just for convenience reasons :-). This would
enable us to encode only at most 128 characters of four-byte UTF-8 characters
(e.g. Klingon in the private use area). I accepted this trade-off and in the end
it turned out that inputting four-byte UTF-8 characters using app.response() was
impossible anyways.
The other end of the service needs to decode the QR code, decrypt the content and
tweet it. This part was a lot easier than the PDF part, as it could be implemented
in less than 50 lines using Ruby and the ZBar
barcode library. A fax number was thankfully provided by AS250.net
so that I only needed to deal with emails from the fax2mail gateway.
If you managed to read this far, you might be interested in the code, which is available
in a Git repository (or see the
Gitweb interface).