Lars Fosdal 1793 Posted August 11, 2023 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
aehimself 399 Posted August 11, 2023 (edited) 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 August 11, 2023 by aehimself Share this post Link to post
Lars Fosdal 1793 Posted August 12, 2023 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
Lars Fosdal 1793 Posted August 13, 2023 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; 1 Share this post Link to post
David Heffernan 2353 Posted August 13, 2023 (edited) 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 August 13, 2023 by David Heffernan Share this post Link to post
Lars Fosdal 1793 Posted August 15, 2023 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
David Heffernan 2353 Posted August 15, 2023 (edited) 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 August 15, 2023 by David Heffernan Share this post Link to post
Lars Fosdal 1793 Posted August 16, 2023 No argument there from me, as I didn't write the code. Share this post Link to post