Jump to content
Lars Fosdal

DCPCrypt v.2.0 - 64-bit?

Recommended Posts

Have any of you used this old lib in 64-bit? It works fine in 32-bit, but I get

Project MyProject.exe raised exception class EDCP_cipher with message 'Unable to allocate sufficient memory for hash digest'.

when running as 64-bit.

 

Curious to know if anyone has worked around this issue already.

Share this post


Link to post

I am using DCPCrypt in 64 bit applications without any issues but I remember that I had to dig for a package as there was one which didn’t compile.

 

I’ll check later today which version I’m using and where exactly I downloaded it from.

 

Edit: ReadMe simply say I'm too using v2 but I cannot find any reference to the sub version number. I still need to confirm this somehow but I think I'm using the SourceForge version.

 

Do you have a code snipplet which fails to compile or it's the package itself?

 

Edit-edit: my archive which has the source is called "dcpcrypt-code-r16-trunk.zip". So I'm pretty sure it's the SourceForge version 🙂

Edited by aehimself

Share this post


Link to post

I figured it out, but I need to do some more checking to figure out why it didn't fail in 32-bit.

Share this post


Link to post

I decided to test switching one my 32-bit apps to 64-bit, to see how it would behave. It uses an encryption algorithm called TwoFish from an old encryption lib - DCPCrypt2 by David Barton- which seems to no longer be maintained, and to my dismay, the encryption failed with a access violation. 

 

Project ConsoleTest.exe raised exception class $C0000005 with message ‘c0000005 ACCESS_VIOLATION’.

 

that was eaten by an exception handler in the lib - which presented a different error message

EDCP_cipher: Unable to allocate sufficient memory for hash digest

 

It fails on the first half of this expression in the code below;

x[1]:= PDWord(longword(@InData)+4)^ xor SubKeys[INPUTWHITEN+1];
i.e. PDWord(longword(@InData)+4)^

 

Question: Longwords and DWords are supposedly the same in both 32-bit and 64-bit, so why does the pointer arithmetic fail in 64-bit?

 

 

Below is the original method that works well in 32-bit, but blows up in 64-bit.
In the DCPtwofish.pas unit:

procedure TDCP_twofish.EncryptECB(const InData; var OutData);
var
  i: longword;
  t0, t1: DWord;
  X: array[0..3] of DWord;
begin
  if not fInitialized then
    raise EDCP_blockcipher.Create('Cipher not initialized');
  x[0]:= PDWord(@InData)^ xor SubKeys[INPUTWHITEN];
  x[1]:= PDWord(longword(@InData)+4)^ xor SubKeys[INPUTWHITEN+1]; // <- 64-bit Access Violation!
  x[2]:= PDWord(longword(@InData)+8)^ xor SubKeys[INPUTWHITEN+2]; 
  x[3]:= PDWord(longword(@InData)+12)^ xor SubKeys[INPUTWHITEN+3];
  i:= 0;
  while i<= NUMROUNDS-2 do
  begin
    t0:= sBox[0,(x[0] shl 1) and $1fe] xor sBox[0,((x[0] shr 7) and $1fe)+1]
      xor sBox[2,(x[0] shr 15) and $1fe] xor sBox[2,((x[0] shr 23) and $1fe)+1];
    t1:= sBox[0,((x[1] shr 23) and $1fe)] xor sBox[0,((x[1] shl 1) and $1fe)+1]
      xor sBox[2,((x[1] shr 7) and $1fe)] xor sBox[2,((x[1] shr 15) and $1fe)+1];
    x[3]:= (x[3] shl 1) or (x[3] shr 31);
    x[2]:= x[2] xor (t0 +   t1 + SubKeys[ROUNDSUBKEYS+2*i]);
    x[3]:= x[3] xor (t0 + 2*t1 + SubKeys[ROUNDSUBKEYS+2*i+1]);
    x[2]:= (x[2] shr 1) or (x[2] shl 31);

    t0:= sBox[0,(x[2] shl 1) and $1fe] xor sBox[0,((x[2] shr 7) and $1fe)+1]
      xor sBox[2,((x[2] shr 15) and $1fe)] xor sBox[2,((x[2] shr 23) and $1fe)+1];
    t1:= sBox[0,((x[3] shr 23) and $1fe)] xor sBox[0,((x[3] shl 1) and $1fe)+1]
      xor sBox[2,((x[3] shr 7) and $1fe)] xor sBox[2,((x[3] shr 15) and $1fe)+1];
    x[1]:= (x[1] shl 1) or (x[1] shr 31);
    x[0]:= x[0] xor (t0 +   t1 + SubKeys[ROUNDSUBKEYS+2*(i+1)]);
    x[1]:= x[1] xor (t0 + 2*t1 + SubKeys[ROUNDSUBKEYS+2*(i+1)+1]);
    x[0]:= (x[0] shr 1) or (x[0] shl 31);
    Inc(i,2);
  end;
  PDWord(longword(@OutData)+ 0)^:= x[2] xor SubKeys[OUTPUTWHITEN];
  PDWord(longword(@OutData)+ 4)^:= x[3] xor SubKeys[OUTPUTWHITEN+1];
  PDWord(longword(@OutData)+ 8)^:= x[0] xor SubKeys[OUTPUTWHITEN+2];
  PDWord(longword(@OutData)+12)^:= x[1] xor SubKeys[OUTPUTWHITEN+3];
end;

 

The answer came from a fellow developer elsewhere:

It fails because pointers are not longwords in 64 bit and casting to longword clips the upper 32 bits, so the cast of a pointer to a longword is not the way to do it.

Instead - the correct way would be to change the expression to PDWord(UIntPtr(@InData)+4)^

 

After some fiddling in the debugger, I thought - why not try a cleaner approach to the pointer casts, and this is what I came up with - and it works as intended in both 32-bit and 64-bit, without the explicit offset calculations.  

type
  ArrDWord = array[0..3] of DWord;
  pArrDWord = ^ArrDWord;

procedure TDCP_twofish.EncryptECB(const InData; var OutData);
var
  i: longword;
  t0, t1: DWord;
  X: array[0..3] of DWord;
begin
  if not fInitialized then
    raise EDCP_blockcipher.Create('Cipher not initialized');
  x[0]:= PArrDWord(@InData)[0] xor SubKeys[INPUTWHITEN];
  x[1]:= PArrDWord(@InData)[1] xor SubKeys[INPUTWHITEN+1];
  x[2]:= PArrDWord(@InData)[2] xor SubKeys[INPUTWHITEN+2];
  x[3]:= PArrDWord(@InData)[3] xor SubKeys[INPUTWHITEN+3];
  i:= 0;
  while i<= NUMROUNDS-2 do
  begin
    t0:= sBox[0,(x[0] shl 1) and $1fe] xor sBox[0,((x[0] shr 7) and $1fe)+1]
      xor sBox[2,(x[0] shr 15) and $1fe] xor sBox[2,((x[0] shr 23) and $1fe)+1];
    t1:= sBox[0,((x[1] shr 23) and $1fe)] xor sBox[0,((x[1] shl 1) and $1fe)+1]
      xor sBox[2,((x[1] shr 7) and $1fe)] xor sBox[2,((x[1] shr 15) and $1fe)+1];
    x[3]:= (x[3] shl 1) or (x[3] shr 31);
    x[2]:= x[2] xor (t0 +   t1 + SubKeys[ROUNDSUBKEYS+2*i]);
    x[3]:= x[3] xor (t0 + 2*t1 + SubKeys[ROUNDSUBKEYS+2*i+1]);
    x[2]:= (x[2] shr 1) or (x[2] shl 31);

    t0:= sBox[0,(x[2] shl 1) and $1fe] xor sBox[0,((x[2] shr 7) and $1fe)+1]
      xor sBox[2,((x[2] shr 15) and $1fe)] xor sBox[2,((x[2] shr 23) and $1fe)+1];
    t1:= sBox[0,((x[3] shr 23) and $1fe)] xor sBox[0,((x[3] shl 1) and $1fe)+1]
      xor sBox[2,((x[3] shr 7) and $1fe)] xor sBox[2,((x[3] shr 15) and $1fe)+1];
    x[1]:= (x[1] shl 1) or (x[1] shr 31);
    x[0]:= x[0] xor (t0 +   t1 + SubKeys[ROUNDSUBKEYS+2*(i+1)]);
    x[1]:= x[1] xor (t0 + 2*t1 + SubKeys[ROUNDSUBKEYS+2*(i+1)+1]);
    x[0]:= (x[0] shr 1) or (x[0] shl 31);
    Inc(i,2);
  end;
  PArrDWord(@OutData)[0] := x[2] xor SubKeys[OUTPUTWHITEN];
  PArrDWord(@OutData)[1] := x[3] xor SubKeys[OUTPUTWHITEN+1];
  PArrDWord(@OutData)[2] := x[0] xor SubKeys[OUTPUTWHITEN+2];
  PArrDWord(@OutData)[3] := x[1] xor SubKeys[OUTPUTWHITEN+3];
end;

Here is the test code:

uses
  DCPtwofish, DCPsha1;

const
  CRYPT_KEY = 'TheVØryBÆDSecretStr.ing';

function EncryptTwofish(const s: string; Key: string = CRYPT_KEY) : string;
var
  Cipher : TDCP_twofish;
begin
  Result:='';
  Cipher := TDCP_twofish.Create(nil);
  try
      Cipher.InitStr(AnsiString(Key), TDCP_sha1);
      Result := string(Cipher.EncryptString(AnsiString(s)));
  finally
    Cipher.Free;
  end;
end;

procedure TestEncrypt;
begin
  Writeln(EncryptTwoFish('Keep this text a secret'));
end;

 

  • Like 1

Share this post


Link to post

Every time you cast a pointer to a 32 bit integelral value, you are truncating. This is 64 bit porting 101.

 

longword(@InData)

 

That's truncation. 

Edited by David Heffernan

Share this post


Link to post

Spinoff QP entry.

https://quality.embarcadero.com/browse/RSP-42133

Warning when a pointer is cast of a different size integer

 

Consider the following code

procedure Indata(const InData);
var
  X: array[0..1] of DWord;
begin
  x[0]:= PDWord(@InData)^;
  x[1]:= PDWord(LongWord(@InData)+4)^;

This works well in 32-bit, but when you switch to 64-bit, LongWord is still 32-bit, and and casting a pointer to LongWord will then strip the upper 32-bits of the 64-bit pointer and the PDWord pointer will be wrong;

Ideally, the compiler should spot when the integer being cast to a pointer is of a different size (32 vs 64) than the integer type and issue a warning.

Share this post


Link to post

Code is utter shite anyway. Just cast @InData to PDWORD and use pointer arithmetic already. 

 

I would imagine that FixInsight would give the warnings you want. 

Edited by David Heffernan

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×