Jump to content
RTollison

DCPCRYPTO blowfish

Recommended Posts

Trying to sync up a .Net implementation of blowfish and was not syncing up so i added to the dcpcrypto for blowfish.selftest

i added a new key/data items. 

the key3, indata3 and outdata3 then copied the code for encrypt/decrypt and then verify the in/out matched. but my data2 is getting stopped at 8 bytes and not the full 16 in the var section.

 so the EncryptECB is taking it off but i am not sure why. is encryptecb set to only handle 8 bytes/16wide?

class function TDCP_blowfish.SelfTest: boolean;
const
  Key1: array[0..7] of byte= ($00,$00,$00,$00,$00,$00,$00,$00);
  Key2: array[0..7] of byte= ($7C,$A1,$10,$45,$4A,$1A,$6E,$57);
  InData1: array[0..7] of byte= ($00,$00,$00,$00,$00,$00,$00,$00);
  InData2: array[0..7] of byte= ($01,$A1,$D6,$D0,$39,$77,$67,$42);
  OutData1: array[0..7] of byte= ($4E,$F9,$97,$45,$61,$98,$DD,$78);
  OutData2: array[0..7] of byte= ($59,$C6,$82,$45,$EB,$05,$28,$2B);

  Key3: array[0..31] of byte= ($ff,$8a,$0b,$85,$ff,$a9,$14,$d1,$b5,$61,$df,$31,$1f,$94,$f5,$aa,$55,$08,$b9,$ad,$49,$0a,$ba,$df,$e3,$57,$00,$37,$13,$fc,$79,$d0);
  InData3: array[0..15] of byte= ($54,$68,$69,$73,$20,$69,$73,$20,$61,$20,$74,$65,$73,$74,$21,$21);
  OutData3: array[0..15] of byte= ($e2,$77,$9b,$17,$b9,$e4,$2b,$ec,$b7,$a3,$7c,$21,$c0,$d6,$18,$93);
var
  Cipher: TDCP_blowfish;
  Data: array[0..7] of byte;
  Data2: array[0..15] of byte;
begin
  FillChar(Data, SizeOf(Data), 0);
  Cipher:= TDCP_blowfish.Create(nil);
  Cipher.Init(Key1,Sizeof(Key1)*8,nil);
  Cipher.EncryptECB(InData1,Data);
  Result:= boolean(CompareMem(@Data,@OutData1,Sizeof(Data)));
  Cipher.Reset;
  Cipher.DecryptECB(Data,Data);
  Result:= boolean(CompareMem(@Data,@InData1,Sizeof(Data))) and Result;
  Cipher.Burn;
  Cipher.Init(Key2,Sizeof(Key2)*8,nil);
  Cipher.EncryptECB(InData2,Data);
  Result:= boolean(CompareMem(@Data,@OutData2,Sizeof(Data))) and Result;
  Cipher.Reset;
  Cipher.DecryptECB(Data,Data);
  Result:= boolean(CompareMem(@Data,@InData2,Sizeof(Data))) and Result;
  Cipher.Burn;
  Cipher.Free;

  FillChar(Data2, SizeOf(Data2), 0);
  Cipher:= TDCP_blowfish.Create(nil);
  Cipher.Init(Key3,Sizeof(Key3)*8,nil);
  Cipher.EncryptECB(InData3,Data2);
  Result:= boolean(CompareMem(@Data2,@OutData3,Sizeof(Data2))) and Result;
  Cipher.Reset;
  Cipher.DecryptECB(Data2,Data2);
  Result:= boolean(CompareMem(@Data2,@InData3,Sizeof(Data2))) and Result;
  Cipher.Burn;

  Cipher.Free;
end;
procedure TDCP_blowfish.EncryptECB(const InData; var OutData);
var
  xL, xR: DWord;
begin
  if not fInitialized then
    raise EDCP_blockcipher.Create('Cipher not initialized');
  xL:= Pdword(@InData)^;
  xR:= Pdword(longword(@InData)+4)^;
  xL:= ((xL and $FF) shl 24) or ((xL and $FF00) shl 8) or ((xL and $FF0000) shr 8) or ((xL and $FF000000) shr 24);
  xR:= ((xR and $FF) shl 24) or ((xR and $FF00) shl 8) or ((xR and $FF0000) shr 8) or ((xR and $FF000000) shr 24);
  xL:= xL xor PBox[0];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[1];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[2];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[3];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[4];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[5];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[6];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[7];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[8];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[9];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[10];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[11];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[12];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[13];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[14];
  xR:= xR xor (((SBox[0,(xL shr 24) and $FF] + SBox[1,(xL shr 16) and $FF]) xor
    SBox[2,(xL shr 8) and $FF]) + SBox[3,xL and $FF]) xor PBox[15];
  xL:= xL xor (((SBox[0,(xR shr 24) and $FF] + SBox[1,(xR shr 16) and $FF]) xor
    SBox[2,(xR shr 8) and $FF]) + SBox[3,xR and $FF]) xor PBox[16];
  xR:= xR xor PBox[17];
  xL:= ((xL and $FF) shl 24) or ((xL and $FF00) shl 8) or ((xL and $FF0000) shr 8) or ((xL and $FF000000) shr 24);
  xR:= ((xR and $FF) shl 24) or ((xR and $FF00) shl 8) or ((xR and $FF0000) shr 8) or ((xR and $FF000000) shr 24);
  Pdword(@OutData)^:= xR;
  Pdword(longword(@OutData)+4)^:= xL;
end;

 

Share this post


Link to post

Hi, though i have never used DCP i have looked at this https://github.com/SnakeDoctor/DCPcrypt and can elaborate here.

 

7 hours ago, RTollison said:

is encryptecb set to only handle 8 bytes/16wide?

Of course it is !, and what is wide ?

 

thoughts here :

1) there is no wide definition Cipher Blocks algorithms against the usual, there is no such thing, for BlowFish and its SelfTest it is only 64bit (8 bytes) as it should be.

2) BlowFish is 8 bytes block cipher, and you are misunderstood the context of this self test, from what i see this self test looks well defined, and you can't (and must not) introduce or use (for block cipher like blowfish ) a key with 32 bytes, that is wrong, these (almost all) block ciphers algorithms are not standardized (or defined) to handle a key with arbitrary size.

3) same as above (2) only with the data blocks, they are also have specific size with BlowFish it is 8 bytes, with TwoFish and AES is 16 ....

 

Here i am assuming you want to your own self test, or introduce different Test Vectors, so you need the higher level of this implementation for this cipher, the one encapsulate this algorithm, which from what i can see it is TDCP_cipher, this one implement the supported algorithms though TDCP_blockcipher64 or TDCP_blockcipher128, these two does the functionality of longer data handling, aka multiple blocks of data, yet you can't use them, so you really should only use TDCP_cipher for your not only tests but in every usage.

 

Using TDCP_blowfish directly is for only for the who really know what they are doing or who will either stick to only one block or will implement their own higher level encapsulation.

 

Now an important thing to keep in mind and remember always, Block Ciphers works only with defined key length and they can't handle arbitrary key length without introducing another algorithm preferably a standardized one, so stick to the key length for each algorithm, if you are trying to make compatible encryption with different library that is using/accepting arbitrary key length, then you need to emulate/reproduce that part of key trimming/expanding to the accepted key length.

 

in case you want arbitrary key length, then you should look up PBKDF2 algorithm or the less recommended KDF, i can't see these in DCP, so either i don't where to look, you you can just ditch DCP and switch to another library, here comes others who can suggest libraries for you after you extend you need exactly, for me i would not suggest BlowFish for anything, unless there is a legacy data (yes data and not an application), legacy applications should use more modern and more secure algorithms.

 

Hope that was clear.

Share this post


Link to post

The only “issue” I personally experienced with DCPCrypt was string encoding. While a PHP library was working on UTF8, using the built-in functions of DCPCrypt used Unicode - there’s why the end result didn’t match.

Once I converted my string to UTF8 TBytes and encoded that everything started to work perfectly.

Share this post


Link to post

thank you for the info/input. the background on this is that way back in 2014 or prior a dll was create using the DCP Crypto libraries. the blowfish cipher was selected for encrypt/decrypt functions and has been in use for all clients. now a .Net dev was asking me to give him a hand in validating that his .net/c# version is working/matching. he has a quick access point in his code to just encrypt/decrypt the indata value. so we added his test to the selftest for verification. well the first 8 matched but we wanted to determine why the last 8 were not matching to his code. i guess trying to shortcut the testing process was a little short sighted on my part. i will just let it encrypt/decrypt the same string he is testing.

 

Thank you again...

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

×