=head1 NAME CSCI162_RC4 - Perl implementation of ARCFOUR =head1 DESCRIPTION This is an implementation of the ARCFOUR stream cipher (unofficial RC4). =head1 EXPORTS =over 4 =cut package CSCI162_RC4; use warnings; use strict; use Carp; use base 'Exporter'; our @EXPORT = qw/rc4_encrypt rc4_decrypt rc4_encrypt_base64 rc4_decrypt_base64 rc4_translate/; our @EXPORT_OK = @EXPORT; my $BOX_LEN = 256; # raw_to_array $rawstring # Returns the array of byte values in $rawstring. sub raw_to_array ($) { return (unpack('C*',$_[0])); } # array_to_raw $byteval1, $byteval2, ... # Returns a string composed of the byte values of the passed array. sub array_to_raw (@) { return pack('C*',@_); } # raw_to_hex $rawstring # Returns the hex string associated with a string of raw bytes. sub raw_to_hex ($) { return unpack('H*',$_[0]); } # hex_to_raw $hexstring # Returns the raw string associated with an array of hex values. sub hex_to_raw ($) { my $hex = shift; # There must be no leading sign or 0x. $hex =~ s/^-?(?:0[Xx])?//o; # There must be no non-hex digits. $hex =~ s/[^0-9A-Za-z]+//o; # The number of hex digits must be even. $hex = "0$hex" if length($hex) % 2; # Pack it. return pack('H*',$hex); } # key_to_box $key # Returns the box (an array) associated with a key. sub key_to_box ($) { # We want the key that's been input as a byte array. my @key = raw_to_array $_[0]; # First loop sets each element to its index value. # We don't need to do that in Perl, because that's # just a range! my @box = (0 .. $BOX_LEN-1); my $i2 = 0; my $len = scalar @key; # length of key array # The second loop depends on the key string. for(my $i=0; $i<@box; ++$i) { $i2 = ($i2 + $box[$i] + $key[$i%$len]) % $BOX_LEN; # Swap the bytes. ($box[$i],$box[$i2]) = ($box[$i2],$box[$i]); } # That's it. return @box; } =item rc4_encrypt $key, $message Returns a hexadecimal string of the encrypted form of $message. =cut sub rc4_encrypt ($$) { return raw_to_hex( rc4_translate($_[0],$_[1]) ); } =item rc4_decrypt $key, $cipher Returns the decryption of $cipher (which must be passed as hexadecimal). =cut sub rc4_decrypt ($$) { return rc4_translate($_[0], hex_to_raw($_[1])); } # As a bonus, this module will also allow Base64 instead of hex for the # encrypted form. Base64 is an encoding that encodes information from # 3 bytes into 4 7-bit-safe ASCII characters (suitable for sending over # most protocols), versus the 6 that hex would take. use MIME::Base64; =item rc4_encrypt_base64 $key, $plain Returns a Base64 string of the encrypted form of $message. =cut sub rc4_encrypt_base64 ($$) { return encode_base64(rc4_translate($_[0],$_[1])); } =item rc4_decrypt_base64 $key, $cipher Returns the decryption of $cipher (which must be passed as Base64). =cut sub rc4_decrypt_base64 ($$) { return rc4_translate($_[0], decode_base64($_[1])); } =item rc4_translate $key, $rawstring This function actually does all the work of encryption and decryption, which are for all practical purposes identical. The only difference is the input and output format; the encrypt wrappers transcode the output of this function, while the decrypt wrappers transcode the message parameter to this function. This function takes raw data and outputs raw data; it can be used to implement other encodings. =cut sub rc4_translate ($$) { my $i = 0; my $j = 0; # Get the box for this key. my @box = key_to_box $_[0]; # Get the bytes for the message. my @msg = raw_to_array $_[1]; # An array for the output. my @out = (); # Encrypt/decrypt # (This is the PRGA - pseudo-random generation algorithm) for(my $idx=0; $idx < @msg; ++$idx) { # Set the new index values $i = ($i + 1) % $BOX_LEN; $j = ($j + $box[$i]) % $BOX_LEN; # Swap the indices ($box[$i],$box[$j]) = ($box[$j],$box[$i]); # Now, do some xoring push(@out, $msg[$idx] ^ $box[ ($box[$i]+$box[$j]) % $BOX_LEN ]); } # Stringify return array_to_raw @out; } 1; __END__ =back =head1 AUTHORS Written for CSCI 162 Cryptography Spring 2005 at The George Washington University by Anasse Bari and Peter S. May under Dr. Poorvi Vora. =head1 NOTICE This program alleges no compatibility or relationship with the official RC4 stream cipher or with RSA Data Security. =cut