我设法将RC4实现从PolarSSL移植到delphi,因为我需要在两个应用程序(C和Delphi)之间进行加密通信,但问题是,加密数据永远不会相同,两个代码都加密和解密数据他们自己成功但不是由另一方加密的数据。
以下是两个代码:
C代码(取自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;
}
我的德尔福代码:
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 :(得分:10)
我(终于)发现了两个代码之间的差异。
Pascal翻译的以下行不正确:
buf[i+1] := Char(Byte(buf[i+1]) xor Byte(m[a + b]));
C版读取:
buf[i] = (unsigned char) ( buf[i] ^ m[(unsigned char)( a + b )] );
请注意,a + b
被截断为单个unsigned char
,而上面的Pascal版本显示为m[a + b]
,因此a + b
的索引可能超过255。
您应该将此行翻译为:
buf[i+1] := chr(ord(buf[i+1]) xor ord(m[Byte(a+b)]));
我已经改为使用Chr
和ord
,这些都是外观上的变化,但我觉得它们更清洁。实质性更改位于m[Byte(a+b)]
,我强制a+b
添加在字节数据类型的上下文中。
相反,这个错误会导致数组m
的超出范围的数组访问。如果您在启用范围检查的情况下运行,则会立即突出显示该错误。我不能强调德尔福的范围检查功能有多么重要。
答案 1 :(得分:1)
建议:在处理完密钥之后但在加密任何数据之前,请查看两个系统上m[]
数组的内容。显然这两者应该是相同的。如果没有,则问题在于密钥处理。
您可能还想对两个不同的输出进行异或,以查看是否出现任何可能指向您问题的模式。
答案 2 :(得分:1)
这是从.Net翻译的算法的delphi实现:
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.
答案 3 :(得分:0)