2011-08-08 3 views
5

Sono riuscito a portare l'implementazione RC4 da PolarSSL a delphi, poiché ho bisogno di una comunicazione crittografata tra 2 applicazioni (C e Delphi), ma il problema è che i dati crittografati non sono mai gli stessi, entrambi i codici crittografano e decodificano i dati su proprio con successo ma non i dati crittografati dall'altro.RC4 in Delphi e C?

Qui ci sono entrambi i codici:

C Codice (Tratto da 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; 
} 

My Code Delphi:

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

Quella traduzione è di ottimo livello. Qual è la tua domanda? –

+0

i dati crittografati non sono mai gli stessi, quindi i dati crittografati con il codice C non possono essere decifrati dal codice Delphi. – killercode

+0

Sono abbastanza sicuro che ci siano alcuni problemi con l'indice dell'array. Gli array Delphi sono sempre basati su zero? – Milan

risposta

10

Ho (finalmente) trovato una differenza tra i due codici.

La seguente riga della traduzione Pascal non è corretto:

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

La versione C recita:

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

noti che a + b viene troncato in un unico unsigned char, mentre la versione Pascal sopra dice m[a + b] e quindi l'indice di a + b può superare 255.

Si dovrebbe t ranslate questa linea come:

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

ho cambiato usare Chr e ord che sono modifiche estetiche, ma sento che sono più puliti. Il cambiamento sostanziale è in m[Byte(a+b)] in cui impone l'aggiunta a+b nel contesto di un tipo di dati byte.

In modo piuttosto indicativo, questo errore risulta in un accesso dell'array fuori limite dell'array m. Se fossi stato in esecuzione con il controllo intervallo abilitato, il bug sarebbe stato evidenziato immediatamente. Non posso sottolineare abbastanza quanto sia preziosa la funzionalità di controllo del raggio di Delphi.

+1

+1 +10 per persistenza e rilevamento! E per sottolineare l'importanza del controllo del range. –

1

Un suggerimento: esaminare i contenuti degli array m[] su entrambi i sistemi dopo aver elaborato la chiave ma prima di aver crittografato tutti i dati. Ovviamente i due dovrebbero essere identici. In caso contrario, il problema si trova nell'elaborazione delle chiavi.

Si potrebbe anche voler XOR le due uscite diverse per vedere se emergono motivi che potrebbero indicare il problema.

1

Ecco un'implementazione Delphi dell'algoritmo, tradotto dal .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.