2011-08-08 11 views
5

He logrado portar la implementación de RC4 de PolarSSL a delphi, ya que necesito una comunicación encriptada entre 2 aplicaciones (C y Delphi), pero el problema es que los datos cifrados nunca son los mismos, ambos códigos cifran y descifran los datos en su propio éxito, pero no los datos cifrados por el otro.RC4 en Delphi y C?

Éstos son los dos códigos:

C Código (Tomado de PolarSSL)

typedef struct 
{ 
    int x;      /*!< permutation index */ 
    int y;      /*!< permutation index */ 
    unsigned char m[256];  /*!< permutation table */ 
} 
arc4_context; 

void arc4_setup(arc4_context *ctx, unsigned char *key, int keylen) 
{ 
    int i, j, k, a; 
    ctx->x = 0; 
    ctx->y = 0; 
    for(i = 0; i < 256; i++) ctx->m[i] = (unsigned char) i; 
    j = k = 0; 
    for(i = 0; i < 256; i++, k++) 
    { 
     if(k >= keylen) k = 0; 
     a = ctx->m[i]; 
     j = (j + a + key[k]) & 0xFF; 
     ctx->m[i] = ctx->m[j]; 
     ctx->m[j] = (unsigned char) a; 
    } 
    return; 
} 

void arc4_crypt(arc4_context *ctx, unsigned char *buf, int buflen) 
{ 
    int i, x, y, a, b; 
    unsigned char m[256]; 

    x = ctx->x; 
    y = ctx->y; 

    for (i = 0; i < 256; i++) m[i] = ctx->m[i]; 
    for(i = 0; i < buflen; i++) 
    { 
     x = (x + 1) & 0xFF; a = m[x]; 
     y = (y + a) & 0xFF; b = m[y]; 

     m[x] = (unsigned char) b; 
     m[y] = (unsigned char) a; 

     buf[i] = (unsigned char) 
      (buf[i]^m[(unsigned char)(a + b)]); 
    } 
    return; 
} 

Mi Delphi Code:

type 
    arc4_context = packed record 
    x, y: integer; 
    m: array[0..255] of byte; 
    end; 

procedure arc4_setup(var ctx: arc4_context; key: PChar; keylen: Integer); 
var 
i, j, k, a: Integer; 
begin 
ctx.x := 0; 
ctx.y := 0; 
for i := 0 to 255 do ctx.m[i] := Byte(i); 
j := 0; 
k := 0; 
for i := 0 to 255 do 
begin 
    if (k >= keylen) then k := 0; 
    a := ctx.m[i]; 
    j := (j + a + Byte(key[k])) and $FF; 
    ctx.m[i] := ctx.m[j]; 
    ctx.m[j] := a; 
    Inc(k); 
end; 
end; 


procedure arc4_crypt(ctx:arc4_context; var buf:string; buflen:integer); 
var 
i, x, y, a, b: Integer; 
m: array [0..255] of byte; 
begin 
x := ctx.x; 
y := ctx.y; 
for i := 0 to 255 do m[i] := ctx.m[i]; 
i := 0; 
while (i < buflen) do 
begin 
    x := (x + 1) and $FF; 
    a := m[x]; 
    y := (y + a) and $FF; 
    b := m[y]; 

    m[x] := b; 
    m[y] := a; 

    buf[i+1] := Char(Byte(buf[i+1]) xor Byte(m[a + b])); 
    inc(i); 
end 
end; 
+0

que la traducción se ve excelente. ¿Cuál es tu pregunta? –

+0

los datos cifrados nunca son iguales, por lo que los datos cifrados con el código C no se pueden descifrar con el código Delphi. – killercode

+0

Estoy bastante seguro de que hay algunos problemas de índice de matriz. ¿Las matrices Delphi siempre están basadas en cero? – Milan

Respuesta

10

He encontrado (finalmente) una diferencia entre los dos códigos.

La siguiente línea de la traducción Pascal es incorrecto:

buf[i+1] := Char(Byte(buf[i+1]) xor Byte(m[a + b])); 

La versión C lee:

buf[i] = (unsigned char) (buf[i]^m[(unsigned char)(a + b)]); 

Tenga en cuenta que a + b se trunca en un solo unsigned char, mientras que la versión Pascal arriba dice m[a + b] y entonces el índice de a + b puede exceder 255.

Usted debe t ranslate esta línea como:

buf[i+1] := chr(ord(buf[i+1]) xor ord(m[Byte(a+b)])); 

he cambiado a utilizar Chr y ord que son cambios cosméticos, pero siento que son más limpio. El cambio sustancial está en m[Byte(a+b)] donde fuerzo la adición a+b para estar en el contexto de un tipo de datos de bytes.

Bastante revelador, este error da como resultado un acceso de matriz fuera de límites de la matriz m. Si se hubiera estado ejecutando con la verificación de rango habilitada, el error se habría resaltado inmediatamente. No puedo enfatizar lo suficiente la valiosa característica de control de rango de Delphi.

+1

+1 +10 para persistencia y detección! Y para enfatizar la importancia de la verificación de rango. –

1

Sugerencia: observe los contenidos de las matrices m[] en ambos sistemas después de procesar la clave pero antes de cifrar los datos. Obviamente, los dos deberían ser idénticos. Si no, entonces el problema radica en el procesamiento de la clave.

También es posible que desee XOR las dos salidas diferentes para ver si surge algún patrón que pueda señalar el problema.

1

Aquí es una aplicación delphi del algoritmo, traducido del .Net:

unit uRC4; 

interface 

uses Windows; 

type 
    TuRC4 = class 
    public 
     class function RC4(data, key:string):string; 
    end; 

implementation 

class function TuRC4.RC4(data, key:string):string; 
var 
    x, y, j: Integer; 
    box: array[0..255] of Integer; 
    i: Integer; 
    s: String; 

begin 
    for i := 0 to 255 do 
     begin 
     box[i] := i; 
     end; 

    for i := 0 to 255 do 
     begin 
     j := (Ord(key[i Mod Length(key) + 1]) + box[i] + j) Mod 256; 
     x := box[i]; 
     box[i] := box[j]; 
     box[j] := x; 
     end; 

    for i := 0 to Length(data)-1 do 
     begin 
     y := i Mod 256; 
     j := (box[y] + j) Mod 256; 
     x := box[y]; 
     box[y] := box[j]; 
     box[j] := x; 
     s := Char(Ord(data[i + 1]) xor box[(box[y] + box[j]) Mod 256]); 
     Result := Concat(Result, s); 
     end; 
end; 

end.