Delphi和C中的RC4加密算法?

5

我可以帮助您翻译。以下是需要翻译的内容:

我已经成功将PolarSSL中的RC4实现移植到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;
}

我的 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;

那个翻译看起来很棒。你有什么问题吗? - David Heffernan
加密数据永远不会相同,因此用C代码加密的数据不能被Delphi代码解密。 - killercode
我相信这里存在一些数组索引问题。Delphi 数组是否总是从零开始? - Milan
1
@too,编译器可以很好地处理这些转换。 - LU RD
我一直在想为什么人们在翻译 C 标头文件时倾向于使用 "packed"。实际上完全没有必要这样做,而且往往是错误的。 - Rudy Velthuis
显示剩余8条评论
4个回答

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 在C语言中被截断为单个的unsigned char,而上述的Pascal版本则使用了 m[a + b],因此a + b的索引可能超过255。
buf[i+1] := chr(ord(buf[i+1]) xor ord(m[Byte(a+b)]));

我已经改用 Chrord,这只是外观的变化,但我感觉它们更干净。实质性的变化在于 m[Byte(a+b)],其中我强制 a+b 加法运算为字节数据类型。

令人惊讶的是,这个 bug 导致了对数组 m 的越界访问。如果你开启了范围检查功能,该 bug 将会立即被突出显示。我无法强调 Delphi 范围检查功能的价值有多大。


1
+1 +10 的坚持和检测!以及强调范围检查的重要性。 - Marjan Venema

1
一个建议:在处理密钥但尚未加密任何数据之后,查看两个系统中m[]数组的内容。显然,两者应该是相同的。如果不是,则问题出在密钥处理上。
您还可以对两个不同的输出进行异或运算,以查看是否出现任何模式,这可能会指向问题所在。

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.

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接