#!/bin/perl -s-- RC5 in perl5! usage: rc5 -k=<key> -r=<rounds> [-d(ecrypt)] sub M{($m=pop)+($m<0||-($m>~0))*2**32}sub L{($x=pop)<<($n=31&pop)|2**$n-1&$x>> 32-$n}@L=unpack"V*",pack"H*x3",$k;@S=($P=$T=0xb7e15163,map{$T=M$T+0x9e3779b9}0 ..2*$r);sub Y{$_[$_%@_]=L pop,M$_[$_%@_]+M$A+$B}for(0..3*(@S>@L?@S:@L)-1){$A=Y@ S,3;$B=Y@L,M$A+$B}$_='$A=M$A+$S[0];$B=M$B+$S[1]';while(read STDIN,$k,8){($A,$B) =unpack V2,$k."\0"x3;$d||eval;for(1..@S-2){$d?$B=$A^L 32-($A&31),M$B-$S[@S-$_] :($A=M$S[$_+1]+L$B,$A^$B);$A^=$B^=$A^=$B}$d&&(y/+/-/,eval);print pack V2,$A,$B}
RC5 is the subject of research at the moment, it is not a tried and trusted cryptosystem. RSA are requesting papers discussing how RC5 stands up to attacks. RSA has a paper on RC5 by Ron Rivest. If you are in the US, you can request a copy of RSAs reference implementation by sending email to <rc5-administrator@rsa.com>. They request you to confirm that you are a US citizen (the marvels of ITAR). See ITAR disclaimer for their suggested wording. I live in the UK, if you come by a copy I wouldn't say no :-) (My high sec key is on the keyservers, or here :-). I can live without a copy tho' because the paper is available, and Stephen Kapp <skapp@uk.co.compulink.cix> already wrote an implementation of RC5 from the paper for possible inclusion RSAEURO, his plugable replacement for RSADSIs RSAREF library as used by PGP. Also somewhat amusing is that I get the impression that RSA would be happy to surface mail a paper including the source code, just won't export it in electronic form.
RC5 has a variable sized key, and has a variable number of rounds. The number of rounds, and the key size are denoted like this:
RC5-wordsize/rounds/keysize
The wordsize is written in bits, and the keysize in bytes. The perl implementation above has a word size of 32, the key size and rounds are selectable on the command line, with this syntax:
% rc5 -k=1234abcdef1234abcdef -r=12 < plaintext > ciphertextThe key is given in hex, the above corresponds to RC5-32/12/10 because the key is 20 hex nibbles, or 10 bytes long, and because the number of rounds selected (with -r) are 12.
% echo test message | rc5 -e -k=12abcdef -r=12 > test.rc5To decrypt the message you just reverse the process giving the same key and using the encrypted file:
% rc5 -d -k=12abcdef -r=12 < test.rc5You will notice (or more properly you might notice - unix shells seem to silently eat ascii(0)s) that the program pads the decrypted message to a multiple of 8 bytes with ASCII(0)s on decrypt. This is because it can not tell how big the original file was when it is decrypting. If this bothers you and you care, just store the file size either at the begining of the plaintext message so that the size gets encrypted, or store at the begining of the encrypted stream. Then do the appropriate thing on decrypt.
Here is a transcript of execution on a UNIX machine:
% perl -e "print pack(L2,0)" > PLAIN1 % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < PLAIN1 00000000 00000000 % rc5 -k=00000000000000000000000000000000 -r=12 < PLAIN1 > PLAIN2 % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < PLAIN2 eedba521 6d8f4b15
% rc5 -k=915F4619BE41B2516355A50110A9CE91 -r=12 < PLAIN2 > PLAIN3 % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < PLAIN3 ac13c0f7 52892b5b
% rc5 -k=783348E75AEB0F2FD7B169BB8DC16787 -r=12 < PLAIN3 > PLAIN4 % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < PLAIN4 b7b3422f 92fc6903
% rc5 -k=DC49DB1375A5584F6485B413B5F12BAF -r=12 < PLAIN4 > PLAIN5 % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < PLAIN5 b278c165 cc97d184
% rc5 -k=5269F149D41BA0152497574D7F153125 -r=12 < PLAIN5 > RESULT % perl -0777e 'for(unpack("V*",<>)){printf("%lx ",$_);}' < RESULT 15e444eb 249831da