Delphi 和 C 中的 RC4?

发布于 2024-11-28 07:13:21 字数 2331 浏览 1 评论 0原文

我已经设法将 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;
}

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

I've managed to port RC4 implementation from PolarSSL to delphi, since I need an encrypted communication between 2 applications (C and Delphi), but the problem is, the encrypted data is never the same, both codes encrypt and decrypt data on their own successfully but not the data encrypted by the other.

Here are both codes:

C Code (Taken from 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 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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小瓶盖 2024-12-05 07:13:21

我(终于)发现了两个代码之间的区别。

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 的数组访问越界。如果您在启用范围检查的情况下运行,该错误将立即突出显示。我无法充分强调 Delphi 的范围检查功能的价值。

I have (finally) found a difference between the two codes.

The following line of the Pascal translation is incorrect:

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

The C version reads:

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

Note that a + b is truncated into a single unsigned char, whereas the Pascal version above says m[a + b] and so the index of a + b can exceed 255.

You should translate this line as:

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

I've changed to use Chr and ord which are cosmetic changes but I feel they are cleaner. The substantive change is in m[Byte(a+b)] where I force the a+b addition to be in the context of a byte data type.

Rather tellingly, this bug results in an out of bounds array access of the array m. If you had been running with range checking enabled, the bug would have been highlighted immediately. I can't stress enough how valuable Delphi's range checking feature is.

烈酒灼喉 2024-12-05 07:13:21

建议:在处理密钥之后但在加密任何数据之前,查看两个系统上的 m[] 数组的内容。显然两者应该是相同的。如果不是,则问题出在密钥处理上。

您可能还需要对两个不同的输出进行异或,以查看是否出现任何可能指出问题的模式。

A suggestion: look at the contents of the m[] arrays on both systems after you have processed the key but before you have encrypted any data. Obviously the two should be identical. If not then the problem lies in the key processing.

You might also want to XOR the two differing outputs to see if any pattern emerges that might point you to the problem.

〃安静 2024-12-05 07:13:21

下面是该算法的 Delphi 实现,翻译自 .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.

Here is a delphi implementation of the algorithm, translated from .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.
Smile简单爱 2024-12-05 07:13:21

为什么要重新发明轮子?*

我知道DCPCrypt 支持 RC4。

*) 允许出于学术目的

编辑删除。

Why reinvent the wheel?*

I know that DCPCrypt supports RC4.

*) allowed for academic purposes

Edit removed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文