XTEA加密在C和Delphi中提供不同的输出

时间:2011-02-27 09:55:58

标签: c delphi encryption delphi-7

我在C和Delphi上编写应用程序,我在两者中都有XTEA加密,它完全一样 但问题是输出是不同的,即使delta和N是相同的。 我真的不知道什么是错的

这是Delphi代码

type
  TTeaMsgBlock = array[0..1] of LongWord;
  TTeaKeyBlock = array[0..3] of LongWord;

const   
  DELTA = $9e3779b9;
  N = 32;

procedure XTeaCrypt(var V: TTeaMsgBlock; const K: TTeaKeyBlock);
var
  I: LongWord;
  S: Int64;
begin
  S := 0;
  for I := 0 to N - 1 do begin
    Inc(V[0], (((V[1] shl 4) xor (V[1] shr 5)) + V[1]) xor (S + K[S and 3]));
    Inc(S, DELTA);
    Inc(V[1], (((V[0] shl 4) xor (V[0] shr 5)) + V[0]) xor (S + K[(S shr 11) and 3]));
  end;
end;

function XTeaCryptStr(const Msg, Pwd: string): string;
var
  V: TTeaMsgBlock;
  K: TTeaKeyBlock;
  I, L, N: Integer;
begin
  L := Length(Pwd); if L > SizeOf(K) then L := SizeOf(K);
  K[0] := 0; K[1] := 0; K[2] := 0; K[3] := 0; Move(Pwd[1], K[0], L);

  I := 1; L := Length(Msg);
  if L > 0 then SetLength(Result, ((L - 1) div SizeOf(V) + 1) * SizeOf(V))
           else SetLength(Result, 0);
  while I <= L do begin
    V[0] := 0; V[1] := 0;
    N := L - I + 1; if N > SizeOf(V) then N := SizeOf(V);
    Move(Msg[I], V[0], N);
    XTeaCrypt(V, K);
    Move(V[0], Result[I], SizeOf(V));
    Inc(I, SizeOf(V))
  end;
end;

//Test
const Key: array [0..15] of char = (char($00), char($01), char($02), char($03), char($04), char($05), 
                                char($06), char($07), char($08), char($09), char($0a), char($0b), 
                                char($0c), char($0d), char($0e), char($0f));
const Msg: string = 'This Is#';

begin
 WriteLn('Encrypted: ' + pChar(XTeaCryptStr(Msg, Key)));
end.

那就是C代码(取自PolarSSL)

typedef struct
{
    uint32_t k[4];       /*!< key */
} xtea_context;

#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i)                             \
{                                                       \
    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
        | ( (unsigned long) (b)[(i) + 3]       );       \
}
#endif

#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i)                             \
{                                                       \
    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
}
#endif

/*
 * XTEA key schedule
 */
void xtea_setup( xtea_context *ctx, unsigned char key[16] )
{
    int i;

    memset(ctx, 0, sizeof(xtea_context));

    for( i = 0; i < 4; i++ )
    {
        GET_ULONG_BE( ctx->k[i], key, i << 2 );
    }
}

/*
 * XTEA encrypt function
 */
int xtea_crypt_ecb( xtea_context *ctx, int mode, unsigned char input[8],
                     unsigned char output[8])
{
    uint32_t *k, v0, v1, i;

    k = ctx->k;

    GET_ULONG_BE( v0, input, 0 );
    GET_ULONG_BE( v1, input, 4 );

    if( mode == XTEA_ENCRYPT )
    {
        uint32_t sum = 0, delta = 0x9E3779B9;

        for( i = 0; i < 32; i++ )
        {
            v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
            sum += delta;
            v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
        }
    }
    else /* XTEA_DECRYPT */
    {
        uint32_t delta = 0x9E3779B9, sum = delta * 32;

        for( i = 0; i < 32; i++ )
        {
            v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
            sum -= delta;
            v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
        }
    }

    PUT_ULONG_BE( v0, output, 0 );
    PUT_ULONG_BE( v1, output, 4 );
    output[8] = '\0';

    return( 0 );
}

//test
int main()
{
    int i;
    unsigned char buf[8] = "This Is#";
    xtea_context ctx;
    xtea_setup( &ctx, (unsigned char *) xtea_test_key);
    xtea_crypt_ecb( &ctx, XTEA_ENCRYPT, buf, buf );
    printf("Encrypted = %s\n", buf);
    return 0;
}

但输出完全不同:/ 我做错了什么?

4 个答案:

答案 0 :(得分:5)

首先,我没有尝试执行您的代码:我的评论完全基于检查。

怀疑问题的根源是big-endian和little-endian数据存储之间的混淆。

C代码中的宏(GET_ULONG_BE和PUT_ULONG_BE)正在提取原始数据并以BIG-endian格式转换为uint32。

在Delphi中,您将原始数据从字节复制到LongWord格式,而不需要对big-endian进行小端转换。

除此之外,我不确定S作为Int64的声明,但与大端/小端问题相比,这可能是次要的。

编辑: 您需要在XTeaCryptStr()例程中执行big-endian转换。您需要将它应用于密钥结构的4个元素以及数据块 - 在数据进入之前(数据进入)和之后(结果出来)对主加密例程的调用。

编辑:开始尝试运行Delphi代码。第一个问题是您的测试密码以空字符开头。您需要使用不同的密码(没有空字符)。

另一个编辑:

我插入了对SwapEndian()的调用,如下所示:

function XTeaCryptStr(const Msg, Pwd: string): string;
    var
      V: TTeaMsgBlock;
      K: TTeaKeyBlock;
      I, L, N: Integer;
  begin
  L := Length(Pwd);
  if L > SizeOf(K) then
    L := SizeOf(K);
  K[0] := 0; K[1] := 0; K[2] := 0; K[3] := 0;
  Move(Pwd[1], K[0], L);
  for i := 0 to 3 do
    K[i] := SwapEndian( K[i] );

  I := 1; L := Length(Msg);
  if L > 0 then
    SetLength(Result, ((L - 1) div SizeOf(V) + 1) * SizeOf(V))
  else
    SetLength(Result, 0);
  while I <= L do
    begin
    V[0] := 0; V[1] := 0;
    N := L - I + 1;
    if N > SizeOf(V) then
      N := SizeOf(V);
    Move(Msg[I], V[0], N);

    V[0] := SwapEndian( V[0] );
    V[1] := SwapEndian( V[1] );

    XTeaCrypt(V, K);

    V[0] := SwapEndian( V[0] );
    V[1] := SwapEndian( V[1] );

    Move(V[0], Result[I], SizeOf(V));
    Inc(I, SizeOf(V))
    end;
  end;

有了这个(以及一个不包含空字符的密码),我从C和Delphi代码得到了相同的结果。

答案 1 :(得分:4)

您无法从PolarSSL复制代码。

C源代码中存在多个漏洞。 :)

首先, EVER 的ECB加密代码不包括:

output[8] = '\0';

ECB模式的重点是将一个输入块更改为另一个输入块。这条线在ECB例程中没有位置 - 它显然与字符串输出有关。 (事实上​​,这是写入超出缓冲区的末尾; array[n]中的最后一个可写位置是array[n-1]。所以你只是在不相关的内存上涂鸦。由于buf中的测试数组main太短而无法保存自己的ASCII NUL - 将其更改为buf[9],因此可能会使用该行。

我强烈建议针对test vectors测试两个你的C和Delphi代码(对不起该页面上的可怕颜色,除了获取数据并关闭之外没有什么可做的窗口再次快速!:)发现你的程序中哪一个是正确的。

不要使用ECB mode directly。如果使用不当,则很容易提供隐私和完整性保证。在ECB之外构建适当的协议和操作模式是非常困难的工作;请改用OFB, CFB, CTR, CBC, PCBC或其中一种较新的authenticated encryption模式。

编辑您的Delphi中的内容看起来不同:(V[1] xor S)。再看一下C的线条;我认为你在例程的两个关键行中错误地翻译了Delphi版本。(我误读了。抱歉。)

答案 2 :(得分:1)

我不知道为什么我之前的回答是downvotedm然后被删除。

我们再试一次。

如果您在Windows应用程序和微处理器上使用相同的C代码,那么任何标准加密都应该工作只需选择一个。

http://www.drbob42.com/examines/examin92.htm
http://www.hflib.gov.cn/e_book/e_book_file/bcb/ch06.htm(在Delphi中使用C ++代码)
http://edn.embarcadero.com/article/10156#H11

看起来您需要使用DLL,但如果您不想分发它,可以静态链接它

答案 3 :(得分:0)

这是工作代码。我已经从C ++代码转换而来了。 欢呼..;)

unit SuatXTEA;

interface

uses SysUtils;

function EncryptXTEA(Data, Key:AnsiString):AnsiString;
function DecryptXTEA(Data, Key:AnsiString):AnsiString;

implementation

function FourCharsToLong(const V: AnsiString):LongWord;
var j, k:Integer;
begin
 Result:=0;
 for j:=0 to Length(V)-1 do
 begin
  k:=(3-(j mod 4))*8;
  Result:=Result or ((Ord(V[j+1]) shl k));
 end;//for j...
end;//FourCharsToLong

function LongToFourChars(const V: Longword):AnsiString;
var j, k:Integer;
begin
 Result:='';
 for j:=0 to 3 do
 begin
  k:=(3-(j mod 4))*8;
  Result:=Result+AnsiChar(V shr k);
 end;//for j...
end;//LongToFourChars

function HexToDec(Hex:AnsiString):LongWord;
 var j:Integer;
     k:Byte;
     Base:LongWord;
begin
 Result:=0;
 Hex:=UpperCase(Hex);
 Base:=1;
 for j:=Length(Hex) downto 1 do
 begin
  k:=Ord(Hex[j])-48;
  if k>9 then k:=k-7;
  Result:=Result+k*Base;
  Base:=Base*16;
 end;
end;//HexToDec

function EncryptXTEA(Data, Key:AnsiString):AnsiString;
const
 Delta = $9e3779b9;
 NumRounds=32;
var j:Integer;
 B_Key:array [0..3] of LongWord;
 Sum, v0, v1: LongWord;
 B_Result:AnsiString;
begin
 B_Result:='';
 //--- Set Key --------------
 FillChar(B_Key, SizeOf(B_Key), 0);
 j:=0;
 while Key<>'' do
 begin
  B_Key[j]:=FourCharsToLong(Copy(Key, 1, 4));
  Key:=Copy(Key, 5, 1024);
  inc(j);
 end;//while
 //-----
 while Data<>'' do
 begin
  v0:=FourCharsToLong(Copy(Data, 1, 4));
  v1:=FourCharsToLong(Copy(Data, 5, 4));
  Data:=Copy(Data, 9, 1024);
  //---
  Sum:=0;
  for j:= 0 to NumRounds-1 do
  begin
   Inc(v0, (((v1 shl 4) xor (v1 shr 5)) + v1) xor (Sum + B_Key[Sum and 3]));
   Inc(Sum, Delta);
   Inc(v1, (((v0 shl 4) xor (v0 shr 5)) + v0) xor (Sum + B_Key[Sum shr 11 and 3]));
  end;//for j...
  B_Result:=B_Result+LongToFourChars(v0)+LongToFourChars(v1);
 end;//while Data<>''
 //---
 Result:='';
 for j:=0 to Length(B_Result)-1 do
 begin
  Result:=Result+IntToHex(ord(B_Result[j+1]), 2);
 end;
 Result:=Lowercase(Result);
end;//EncryptXTEA

function DecryptXTEA(Data, Key:AnsiString):AnsiString;
const
 Delta = $9e3779b9;
 NumRounds=32;
var j:Integer;
 B_Key:array [0..3] of LongWord;
 Sum, v0, v1: LongWord;
 B_Result:AnsiString;
begin
 //--- Set Key --------------
 FillChar(B_Key, SizeOf(B_Key), 0);
 j:=0;
 while Key<>'' do
 begin
  B_Key[j]:=FourCharsToLong(Copy(Key, 1, 4));
  Key:=Copy(Key, 5, 1024);
  inc(j);
 end;//while
 //-----
 B_Result:='';
 for j:=0 to (Length(Data) div 2)-1 do
 begin
  B_Result:=B_Result+AnsiChar(HexToDec(Copy(Data, (j*2)+1, 2)));
 end;
 //----
 Result:='';
 while B_Result<>'' do
 begin
  v0:=FourCharsToLong(Copy(B_Result, 1, 4));
  v1:=FourCharsToLong(Copy(B_Result, 5, 4));
  B_Result:=Copy(B_Result, 9, 1024);
  //---
  Sum:=$C6EF3720;//Delta*NumRounds = Delta shl 5
  for j:=0 to NumRounds-1 do
  begin
   Dec(v1, (((v0 shl 4) xor (v0 shr 5)) + v0) xor (Sum + B_Key[(Sum shr 11) and 3]));
   Dec(Sum, Delta);
   Dec(v0, (((v1 shl 4) xor (v1 shr 5)) + v1) xor (Sum + B_Key[Sum and 3]));
  end;//for j...
  Result:=Result+LongToFourChars(v0)+LongToFourChars(v1);
 end;//while Data<>''
end;//DecryptXTEA

end.