in reply to perl encryptions keys vs. c
The initial key's state shuffling is different in the two programs, mainly due to the unpack/pack trick (at least in this I did not make a mistake). Quoting from perldoc -f pack:
The "h" and "H" fields pack a string that many nybbles (4-bit groups, representable as hexadecimal digits, 0-9a-f) long.Which I read as: "never, never, never count on it for evaluating portable shuffling keys in ARCFOUR implementations!".Each byte of the input field of pack() generates 4 bits of the result. For non- alphabetical bytes the result is based on the 4 least-significant bits of the input byte, i.e., on "ord($byte)%16". In par- ticular, bytes "0" and "1" generate nyb- bles 0 and 1, as do bytes "\0" and "\1". For bytes "a".."f" and "A".."F" the result is compatible with the usual hexadecimal digits, so that "a" and "A" both generate the nybble "0xa==10". The result for bytes "g".."z" and "G".."Z" is not well-defined.
The initial shuffling in the C program is even more akward, if possible: trying to interpret characters out of [0-9a-fA-F] as hexadecimal can lead to a situation in which the input key is virtually ignored (for example, key "zentara!" leads to "AAAAAAAA" in hex, much like "pppppppp"...).
To make both programs use the same shuffling data, I've simply used the input key - how good this system is I leave to the experts. This is straightforward in C, and requires a bit of map mangling in Perl (C has to be better for something. :-) Interworking has been tested on a very little test file, I leave further analysis to the interested ones.
The Perl modified code is the following. I've added strict and warnings just to be sure that there wasn't anything spoiling the output under the hood. The shuffling array @k is evaluated from the input key applying ord() to each input char. Yes, I could use unpack() instead of split().
The C code is virtually unmodified (for being a C code, of course). I added a couple of includes and removed some unneeded variables to shut the warnings off (-Wall was added for the same reasons I used strict and warnings). Of course, I eliminated the initial key mangling to make the program use it directly for state shuffling inside key.#!/usr/bin/perl -0777 -- # $0 key infile > outfile # symmetric works both ways use strict; use warnings; my @k = map { ord($_) } split //, shift; my (@s, $x, $y); $y = 0; for ( my @t = @s = 0 .. 255 ) { $y = ( $k[ $_ % @k ] + $s[ $x = $_ ] + $y ) % 256; &S; } $x = $y = 0; for ( unpack( 'C*', <> ) ) { $x++; $y = ( $s[ $x %= 256 ] + $y ) % 256; &S; print pack( 'C', $_ ^= $s[ ( $s[$x] + $s[$y] ) % 256 ] ); } sub S { @s[ $x, $y ] = @s[ $y, $x ] }
As a final note, it has to be observed that the C approach seems more robust for large input files: read a chunk of data, encrypt and write. In the Perl version, slurp mode in input (according to "-0777") makes the process read the entire file in memory before analysing it. Transforming the encription cycle in the Perl source is left as an exercise for the memory impaired Monk./* gcc -o rc4 rc4.c -Wall */ #include <stdio.h> #include <string.h> #include <stdlib.h> #define buf_size 1024 typedef struct rc4_key { unsigned char state[256]; unsigned char x; unsigned char y; } rc4_key; #define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t void dumphex(unsigned char* data, unsigned long size) { unsigned long i; printf("%lu elementi\n\t", size); for (i = 0; i < size; ) { printf("%02X ", data[i]); if (! (++i % 16)) { printf("\n\t"); } } printf("\n"); } void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_ke +y *key) { unsigned char t; unsigned char index1; unsigned char index2; unsigned char* state; short counter; state = &key->state[0]; for(counter = 0; counter < 256; counter++) state[counter] = counter; key->x = 0; key->y = 0; index1 = 0; index2 = 0; for(counter = 0; counter < 256; counter++) { index2 = (key_data_ptr[index1] + state[counter] + index2) % 256; swap_byte(&state[counter], &state[index2]); index1 = (index1 + 1) % key_data_len; } } void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key) { unsigned char t; unsigned char x; unsigned char y; unsigned char* state; unsigned char xorIndex; short counter; x = key->x; y = key->y; state = &key->state[0]; for(counter = 0; counter < buffer_len; counter++) { x = (x + 1) % 256; y = (state[x] + y) % 256; swap_byte(&state[x], &state[y]); xorIndex = (state[x] + state[y]) % 256; buffer_ptr[counter] ^= state[xorIndex]; } key->x = x; key->y = y; } int main(int argc, char* argv[]) { char seed[256]; char buf[buf_size]; int rd; rc4_key key; if (argc < 2) { fprintf(stderr,"%s key <in >out\n",argv[0]); exit(1); } strcpy(seed,argv[1]); prepare_key(seed, strlen(seed), &key); rd = fread(buf,1,buf_size,stdin); while (rd>0) { rc4(buf,rd,&key); fwrite(buf,1,rd,stdout); rd = fread(buf,1,buf_size,stdin); } return 0; }
Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')
Don't fool yourself.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: perl encryptions keys vs. c
by zentara (Cardinal) on Apr 24, 2005 at 11:04 UTC |