开发者

XTEA encryption give different output in C and Delphi

I'm coding an application on both C and Delphi, I've XTEA Encryption in both, its exactly the same but the problem is the output is different, even though the delta and N is the same. I don't really know whats wrong

Here is the Delphi code

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.

and thats the C code (Taken From 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&开发者_如何转开发gt;>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;
}

but the output is totally different :/ What am I doing wrong?


Firstly, I have not tried to execute your code: my comments are based purely on inspection.

I suspect the root of your problem is confusion between big-endian and little-endian data storage.

The macros in the C code (GET_ULONG_BE and PUT_ULONG_BE) are extracting the raw data and converting to uint32 in BIG-endian format.

In Delphi, you are copying the raw data from bytes to LongWord format without doing a little-endian to big-endian conversion.

Apart from that, I'm not sure about the declaration of S as Int64, but that is probably minor in comparison to the big-end/little-end problem.

Edit: You need to do the big-endian conversion in your XTeaCryptStr() routine. You need to apply it to the 4 elements of the key structure, and to your data block - both before (the data going in) and after (the result coming out) the call to the main encryption routine.

Edit: Started trying to run the Delphi code. First problem is that your test password starts with a nul character. You need to use a different password (without nul characters).

Yet another edit:

I inserted calls to SwapEndian() as below:

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;

With this (and a password that doesn't contain nul characters), I got the same result from the C and Delphi code.


You have failed copying the code from PolarSSL.

There are several bugs in the C source that were the tip-off. :)

First, no ECB encryption code would EVER include:

output[8] = '\0';

The whole point of ECB mode is to change one block of input into another block of input. This line has no place in an ECB routine -- it is obviously related to string-output. (In fact, this is also writing beyond the end of the buffer; the last writable position in array[n] is array[n-1]. So you're just scribbling on unrelated memory. This line was probably put into place because the test array buf in main is too short to hold its own ASCII NUL -- change that to buf[9].)

I would strongly suggest testing both your C and Delphi code against test vectors (sorry about the horrible colors on that page, nothing to be done about it except get the data and close the window again quickly! :) to discover which, if either, of your programs are correct.

PLEASE do not use ECB mode directly. When used improperly, it is too easy to provide zero privacy and integrity assurances. Building proper protocols and modes of operation out of ECB is very difficult work; please use OFB, CFB, CTR, CBC, PCBC or one of the newer authenticated encryption modes instead.

EDIT: This in your Delphi looks different: (V[1] xor S). Take another look at the lines from C; I think you've mis-translated the Delphi version in the two key lines of the routine. (I misread. Sorry.)


I don't know why my previous answer was downvotedm then deleted.

Let's try again.

If you use the same C code in your Windows app and on the microprocessor then any standard encryption should work Just choose one.

See

http://www.drbob42.com/examines/examin92.htm
http://www.hflib.gov.cn/e_book/e_book_file/bcb/ch06.htm (Using C++ Code in Delphi)
http://edn.embarcadero.com/article/10156#H11

It looks like you need to use a DLL, but you can statically link it if you don't want to distribute it


Here is the working code. I've converted from the C++ code. cheers.. ;)

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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜