mhumm / delphiencryptioncompendium Goto Github PK
View Code? Open in Web Editor NEWCryptographic library for Embarcadero Delphi and potentially for FPC as well
License: Apache License 2.0
Cryptographic library for Embarcadero Delphi and potentially for FPC as well
License: Apache License 2.0
Not so sure this is a bug, but I want to use the compendium in D2010 and having trouble.
I certainly don't want to use the installer project as I don't want it installed everywhere, but from what I could see, it basically just installs library paths, which I have done manually for a test project.
It has also been written for Delphi versions greater than D2010 since the uses clause for example is like:
uses
System.SysUtils,
System.Win.Registry,
System.Classes;
which don't work for D2010 and changing these just leads me further down a rabbit hole.
Anyhow, just setting the path in the project options then gives me the compiler error:
[DCC Error] DECOptions.inc(98): E2029 $IFEND expected but $ENDIF found
{$IFDEF FPC }
{$IF defined(CPUX86_64) or defined(CPUAMD64) or defined(CPUIA64) }
{$ifndef CPUX64}
{$define CPUX64}
{$endif}
{$else}{$if defined(CPU386) or defined(CPUI386) }
{$ifndef CPUX32}
{$define CPUX32}
{$endif}
{$ELSE}
{$IFNDEF ASSEMBLER }
{$DEFINE NO_ASM} (* default ON )
{$ELSE}
{$IFDEF WINDOWS}
{.$DEFINE NO_ASM} ( default OFF )
{$ELSE}
{$DEFINE NO_ASM} ( default ON *)
{$ENDIF}
{$ENDIF}
{$ENDIF}{$endif} // line 98
{$ELSE}
// Turn ASM off for FPC as we do not know enough about ASM support on FPC
{$DEFINE NO_ASM}
{$ENDIF}
FPC is not set so don't see why that line is even reached.
Removing what looks like an extra {$endif} doesn't help.
Had some success replacing both the {$ENDIF}{$endif} with {$IFEND}{$ifend}, which required me to start removing the 'system.' prefix of a lot of the uses clauses in many other units, but that rabbit hole got to deep with other errors that I won't go into here.
If I set FPC then I just get an error in Indy10 with:
[DCC Error] IdCompilerDefines.inc(528): E1030 Invalid compiler directive: 'MODE'
So the question I'm asking is, has anyone got this working with D2010 recently and can they tell me what I should do?
You told me a few days that it would be preferrable if the padding would be randomized instead of static.
I have researched on the topic and indeed, randomized padding for the last block is highly recommended.
I have tried to find out how it currently works, but I believe that the documentation does not fit the code
Documentation:
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
vs. Implementation (This is the only place where I could see that IFillter
is used):
FillChar(FInitializationVector^, FBufferSize, IFiller)
The I
is probably also a hint that the filler is the padding of the IV and not the padding of the last block?
So a few questions arrised:
IFiller
is only for the IV, are we safe then? (Because the blocks are dependant on each previous block, so the padding of the last block will be rather unguessable.) Edit: To answer my own question: We might be more safe if we'd use the standard PKCS#7 to fill the last block.FillChar(FInitializationVector^, FBufferSize, IFiller)
Why is the IV filled with the length of the buffer size, and not with the length of the block? I thought the IV only needs the size of a single block, and not the size of the buffer?In case we want random padding, I guess we could use TBlockFillMode
for this purpose; something like:
if FillMode = fmByte then
FillChar(FInitializationVector^, FBufferSize, IFiller)
else if FillMode = fmRandomByte then
FillChar(FInitializationVector^, FBufferSize, ....Random stuff....);
Edit: Actually, if we use TBlockFillMode as it is intended to be (to fill the last block instead of the IV), then it might be good to have it actually be defined as (fmByte, fmRandom, fmPkcs5, fmPkcs7)
where fmByte
is defined as constant byte.
Sorry decryption is solved by myself
Describe the bug
Incorrect auth tag generated for GCM mode when feeding data using small chunks (at least when sized to cipher's block size). Using such small chunks appear to conform with DEC's documentation.
To Reproduce
procedure TestTDECGCM.TestEncodeStreamChunked;
begin
// Use cipher block size as max chunk size
DoTestEncodeStream_LoadAndTestCAVSData(
Max(FCipherAES.Context.BlockSize, FCipherAES.Context.BufferSize));
end;
Expected and actual behavior
Test should pass, proving that expected auth tag is generated when streaming data in small chunks.
##1. Currently Haval hashes have "hardcoded" rounds value:
· THash_Haval128 = 128/3
· THash_Haval160 = 160/3
· THash_Haval192 = 192/4
· THash_Haval224 = 224/4
· THash_Haval256 = 256/5
~~ Would be helpful to allow to set Rounds value in constructor.
##2. Problem currently is that FCount (rounds) value is reset to "0" in
"TDECHash.Init;" - called in CalcBuffer (CalcBinary), so even user created an
object:
Haval := THash_Haval256.Create;
Haval.Rounds := 4;
Haval.CalcBinary(Str, DECFmt.TFormat_HEXL);
Haval.Free;
= would have no effect, because .SetRounds is called twice - 1st to "4", then
2nd time by Init resets to "0", which will then results in default "5" value
for 256 digest..
##3. Some of Hash functions have counterintuitive names:
· THash_Whirlpool = is actually Whirlpool-0
· THash_Whirlpool1 = Whirlpool-T
· And Whirlpool/Whirlpool-2 = not implemented..
##4. Implemented "THash_Tiger" has is actually:
· Tiger (192/3)
~~ Would be helpful to change name / implement / allow to set Digest and
Rounds..
For example:
· Tiger (128/3), · Tiger (160/3), · Tiger (192/3)
· Tiger (128/4), · Tiger (160/4), · Tiger (192/4)
##5. Would be useful to add "SHA-2 (224)" Hash
------------------------------------------------
## Current Haval workaround - manually calling all "Init, manual set, Calc"
code:
program Project1;
{$AppType Console}
uses
DECHash,
DECFmt;
function Haval_Str(Str: string; DS: Integer; Rounds: Byte = 5): string;
var
Haval: THashBaseHaval;
begin
Result := '';
case DS of
128: Haval := THash_Haval128.Create;
160: Haval := THash_Haval160.Create;
192: Haval := THash_Haval192.Create;
224: Haval := THash_Haval224.Create;
256: Haval := THash_Haval256.Create;
end;
try
Haval.Init; //Called by CalcBinary/CalcBuffer == Resets any customizations made..
Haval.Rounds := Rounds; //override value.
Haval.Calc(Str[1], Length(Str));
Haval.Done;
Result := Haval.DigestStr(DECFmt.TFormat_HEXL);
finally
Haval.Free;
end;
end;
var
d, r: Integer;
begin
for r := 3 to 5 do
begin
d := 128;
repeat
Writeln( 'haval (', d, '/', r, '): ', Haval_Str('test', d, r) );
inc(d, 32);
until (d > 256);
Writeln;
end;
Readln;
end.
------------------------------------------------
Original issue reported on code.google.com by [email protected]
on 14 Nov 2012 at 5:20
To Reproduce
Usually, if you change the cipher mode after the cipher has been initialized, then TDECCipher.SetMode
should call Done
on the cipher and re-initialize it.
GCM Encode requires that TGCM.Init
is called and has set FEncryptionMethod := EncryptionMethod
. However, if Ciper.Mode
is set after the cipher has been initialized, then TGCM
is created but TGCM.Init
has not been called.
procedure TDECCipherModes.InitMode;
begin
if FMode = TCipherMode.cmGCM then
begin
if Context.BlockSize = 16 then
FGCM := TGCM.Create
else
// GCM requires a cipher with 128 bit block size
raise EDECCipherException.CreateResFmt(@sInvalidBlockSize,
[128, GetEnumName(TypeInfo(TCipherMode),
Integer(FMode))]);
end
else
if Assigned(FGCM) then
FreeAndNil(FGCM);
end;
The program flow if Mode has been set before init:
FGCM.Init(self.DoEncode, OriginalInitVector)
)The program flow if Mode has been set after init:
OriginalInitVector
from )So... what do we do? We probably need to preserve the InitVector, so we can call TGCM.Init with the correct parameters.
The other solution is to forbid to change the mode after the cipher has been initialized. But this is a code breaking change.
What steps will reproduce the problem?
1. Create a TChiper_2DES object
2. Encrypt using double-length key (16 bytes)
3. Compare to results using doubled single-length key with same first half as
in #2
What is the expected output? What do you see instead?
Results from #3 should be different than results from #2, but are always the
same, equivalent to single DES.
What version of the product are you using? On what operating system?
Version 5.2, Win 7 64-bit, Delphi 2010 Version 14.0.3593.25826
Please provide any additional information below.
Strangely, decrypt works correctly. Use
http://people.eku.edu/styere/Encrypt/JS-DES.html to test, as it does both
single and triple DES.
Original issue reported on code.google.com by [email protected]
on 17 Aug 2012 at 3:09
DEC's SCOP implementation is broken. I noticed this while porting the older version of the library (the "unofficial fork", as you call it) to PowerPC.
The array indices in these 3 lines all need to be + 1 like the first one, else they read out-of-bounds data when I
>= 4. Also refer to the original spec.
On big endian processors the byte order of the following 32-bit array in the struct is different, which is why it was causing different results than on little endian processors. It had me quite confused for a couple hours.
PS: I've seen your issue in my repository and will provide my views on the matter soon-ish.
The current release contains a few features not supported in XE2
To Reproduce
Open XE2
try to compile any 32bit project, that uses DEC (I haven't tried to compile 64bit)
Details
I'm having Abstract error: TDECHashAuthentication is not implemented
error when calling PBKDF2 function
aes_key, Password, Salt : TBytes;
...
aes_key := TDECHashAuthentication.PBKDF2( Password, Salt, 100000, 32 );
In the TDECHashAuthentication source code there are no implementation of DigestSize, and the exception raised from here:
class function TDECHash.DigestSize: UInt32;
begin
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
Please help, how to make working PBKDF2 ?
[help wanted, delphi, question]
I have just installed the library via Getit Package Manager on Delphi 10.3 Version 26.0.36039.7899
Restarted IDE
But able compile nothing:
[dcc32 Fatal Error] test.pas(8): F2613 Unit 'DECCipherBase' not found.
Could you help, what should I do to next? Thanks
The XTEA cipher algorithm seems to be broken. It differs from the various C-implementations one can find on the internet in so far that brackets are set differently and thus the result differs as well. This is at least the case since DEC V5.2 even if it passes its DUnitTest in DEC 6.0 development, so that also means that the test data is most likely wrong. The source of this test data is unfortunately unclear. It already was that way before I took over maintenance of this library.
A fixed development branch commit should be available soon.
I am trying to migrate from the DEC 5.2 version to the current one for Linux. I have written my own wrapper for the old version of the library and I use this wrapper in my projects. But I see very many changes in the new DEC, I have dozens of compilation errors.
Please help me how to approach this migration.
uses DecUtil, DECCipher, DECHash, DECFmt;
var
ACipherClass: TDECCipherClass = TCipher_Rijndael;
ACipherMode: TCipherMode = cmCBCx;
AHashClass: TDECHashClass = THash_Whirlpool;
ATextFormat: TDECFormatClass = TFormat_Mime64;
AKDFIndex: LongWord = 1;
function Encrypt(const AText: WideString; const APassword: WideString): WideString;
var
ASalt: Binary;
AData: Binary;
APass: Binary;
begin
with ValidCipher(ACipherClass).Create, Context do
try
ASalt := .... ;
APass := ValidHash(AHashClass).KDFx(APassword[1], System.Length(APassword) * SizeOf(APassword[1]), ASalt[1], System.Length(ASalt), KeySize, TFormat_Copy, AKDFIndex);
Mode := ACipherMode;
Init(APass);
SetLength(AData, System.Length(AText) * SizeOf(AText[1]));
Encode(AText[1], AData[1], System.Length(AData));
Result := ValidFormat(ATextFormat).Encode(ASalt + AData + CalcMAC);
finally
Free;
end;
end;
I'd like to use DEC for creating One Time Passwords (OTP) such as Google Authenticator, but this requires Base32 encoding support
RFC 4226
Describe the bug
Readme.md has the line "- Key deviation algorithms".
Expected and actual behavior
Should not it be "- Key derivation algorithms" instead?
I am trying to migrate from the archaic DEC version to the current one. I have written my own wrapper for the old version of the library and I use this wrapper in my projects.
But I see very many changes in the new DEC, I have dozens of compilation errors. Please give me some words how to approach this migration.
I noticed for example that the new DEC is focused on using TBytes type, am I right? What else to pay attention to?
Hello,
Would Keccak be implemented (224, 256, 384 and 512)?
Best regards.
If I compile the Library for Linux as target Plattform an error occurs:
[DCC Fehler] DECHash.pas(325): E2100 Datentyp zu groß: 2 GB überschritten
Line 325 in DECHash:
TBABytes = array[0..MaxLongInt-1] of UInt8;
In the demos, there is a typo "VLC" instead of "VCL".
Since it affects renaming files, I feel more secure if you do it directly instead of a pull request.
Thank you!
The simple cipher demo does not use a KDF to generate a key and instead uses a password that has the right length to be accepted by the used cipher. Since developers (myself included) often start with copying code from the demo, it would be cool, if there was a demo, that uses the library in a safe way with an unbroken cipher.
The goal here is, that developers, which are new to cryptography or this library, won't end up with weak encryption in their projects.
The following cipher algorithms do not properly pass their unit tests on x64 currently:
They do pass their unit tests on x32 platform.
I haven't tested this on mobile platforms yet.
Any help in testing and fixing these issues is welcome.
I was trying to hash large TFileStream (all except the first 10MB of the file). I'm using a 900MB file in testing.
When I call Hash.CalcStream(...) on the TFileStream I get an Integer Overflow exception (EIntOverflow).
Tested with THash_SHA256 and THash_SHA512
To Reproduce
Run the following:
uses DECHash;
procedure TfrmTest.Button1Click(Sender: TObject);
var
fsIn: TFileStream;
b: TBytes;
begin
fsIn:=TFileStream.Create('900MBfile.dat', fmOpenRead);
try
fsIn.Seek(10000000, soFromBeginning); //skip the first 10 MB
b:=HashStream_SHA256(fsIn);
finally
fsIn.Free;
end;
System.IOUtils.TFile.WriteAllBytes('hash.bytes', b);
end;
function TfrmTest.HashStream_SHA256(s: TFileStream): TBytes;
var
Hash : THash_SHA256;
HashResult: TBytes;
begin
Hash:=THash_SHA256.Create;
try
Hash.CalcStream(s, s.Size - s.Position, HashResult);
finally
Hash.Free;
end;
result:=HashResult;
end;
Expected and actual behavior
Expected HashResult to be populated with the hash bytes and no excpetions raised.
Actual behavior: An exception is thrown when hashing large files using CalcStream().
When I use a small file (around 15MB) there is no exception and it functions as normal.
I have a project group that uses the DEC code base to replace some older DCrypt units.
There are two projects sharing the same code: one is compiled as a console EXE that runs a web server under localhost, the other is an ISAPI dll. So apart from the DPR file the code base is the same.
I can compile the EXE, but the DLL compilation fails with this error
[dcc64 Error] DECCipherInterface.pas(746): E2134 Type '<void>' has no type info
Commenting out the line at 486 in this unit
procedure Init(const Key; Size: Integer; const IVector; IVectorSize: Integer; IFiller: Byte = $FF); overload;
allows compilation to succeed.
This method declaration contains an untyped parameter. Is this causing the failure ?
And if so why does it compile under the EXE but not the DLL?
This is the only really left thing of #2:
implement the Tiger128 and Tiger160 hash algorithms.
While this can be done and will eventually done importance of this is considered to be low.
The Hash FMX demo app crashes when compiled as release mode Android 32 app. When compiled as Android 32 bit debug mode app it works. The reason is not known yet but it will be investigated.
Some user reported that this code is sufficient to crash it already:
`uses
DECHash
var
Hash: THash_MD5;
begin
Hash := THash_MD5.Create;
Try
sleep(1000);
Finally
Hash.Free;
End;`
Preface
I'm updating very (very!) old code that used DEC3 by using the latest version available at time of writing.
For backward compatibility reasons I have to make sure (for now) that ciphers encoded/decoded are identical to DEC3, so I enabled compatibility mode (DEC3_CMCTS) for 3-DES and fixed the DecodeCTS3 method which was missing the TDECCipherModes class in the implementation (which is also a minor bug in current DECCipherModes unit).
When I compared the output of the new DEC6 cipher implementation against that of DEC3 I saw they were not identical.
After some investigation I noticed something that strikes me odd in the implementation of the 2DES and 3DES cipher DoEncode and DoDecode methods and after changing it in the library, the results were identical to DEC3 again.
Also, when comparing the implementation of 2DES and 3DES to other DES ciphers (like 2DDES and 3DDES) it appears that both 2DES and 3DES contain the same bug.
Describe the bug
Implementation of 3DES DoEncode- and DoDecode-methods (for 2DES it's similar, but not checked myself):
procedure TCipher_3DES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[ 0]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[64]);
end;
procedure TCipher_3DES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[160]);
end;
If I correctly understand the code, the first call to DES_Func will take the Source and put the result in Dest, but the second and third call to DES_Func will also take the original Source and will each overwrite Dest again, resulting in only the last call being effective on the output, resulting in an erroneous result.
Expected and actual behavior
When I change the code to the following, the result is as expected:
procedure TCipher_3DES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[ 0]);
DES_Func(Dest, Dest, @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(Dest, Dest, @PUInt32Array(FAdditionalBuffer)[64]);
end;
procedure TCipher_3DES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(Dest, Dest, @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(Dest, Dest, @PUInt32Array(FAdditionalBuffer)[160]);
end;
I haven't checked 2DES myself, but the problem appears to be there as well.
please add Argon2
it's the default now
A define akin to DEC 3.0's ManualRegisterClasses would be nice to have. All the XXX.RegisterClass() calls in "initialization" section of a few modules could be surrounded by {$IFNDEF ManualRegisterClasses}.
The define could be placed in DECOptions.inc as disabled by default.
Decrypting data and encrypting back the result of first step should output the starting value.
This has been broken with lastest version, using class TCipher_2DES. Not tested all the des function, possible bug also in other des classes due the new refactoring on the DES unit.
Test output with version 6.4
Test output with version 6.3
(as previously mentioned in #62 )
I am using Delphi 11, have compiled DEC60.exe to compile the DCU files and then immediately compiled and ran DECUnitTestSuite.exe
There are the following problems "out of the box":
TestEncodeStreamChunked: ETestFailure
at $00344DD3
Authentication tag wrong for Key 9971071059abc009e4f2bd69869db338 IV 07a9a95ea3821e9c13c63251 PT f54bc3501fed4f6f6dfb5ea80106df0bd836e6826225b75c0222f6e859b35983 AAD Exp.: Act.: , expected: <7870d9117f54811a346970f1de090c41> but was: <12dee761e7034c3fe993d7bfb3389aa9>
The vector is from gcmEncryptExtIV128.rsp
[Keylen = 128]
[IVlen = 96]
[PTlen = 256]
[AADlen = 0]
[Taglen = 128]
Count = 0
Key = 9971071059abc009e4f2bd69869db338
IV = 07a9a95ea3821e9c13c63251
PT = f54bc3501fed4f6f6dfb5ea80106df0bd836e6826225b75c0222f6e859b35983
AAD =
CT = 0556c159f84ef36cb1602b4526b12009c775611bffb64dc0d9ca9297cd2c6a01
Tag = 7870d9117f54811a346970f1de090c41
I guess this is the same as #52 (comment)
I tried to compile 3de on linux, and got
C:\.....\DelphiEncryptionCompendium\DECUtil.pas(627,24): error E2003: E2003 Undeclared identifier: 'GetTickCount64'
FMX on windows works fine
with TCipher_3DES.Create do
try
Mode:=cmCBCx;
Init('5oquil2oo2vb63e8ionujny6','12345678');
Decoded := DecodeBinary ('y/3R651R/AnKxkdtFkUZpihKnpKe9Orx',TFormat_MIME64 );
Free;
end;
In the examples we can see the following usage of encryption:
// Encrypt
Output := Cipher.EncodeBytes(Input);
// clean up inside the cipher instance, which also removes the key from RAM
Cipher.Done;
// Decrypt
Cipher.Init(RawByteString(StringOf(KeyKDF)), IV, 0);
Output := Cipher.DecodeBytes(Output);
// clean up inside the cipher instance, which also removes the key from RAM
Cipher.Done;
The documentation of TDECCipher.Done says:
/// Properly finishes the cryptographic operation. It needs to be called
/// at the end of encrypting or decrypting data, otherwise the last block
/// or last byte of the data will not be properly processed.
(You probably also want to add the argument "removes the key from RAM" in that documentation)
I am confused about the argument "last block or last byte of data will not be properly processed". The Done
method does not return data, so it looks like the "processing of the last block" is useless??
Cipher.Init(RawByteString(StringOf(KeyKDF)), IV, 0);
Output := Cipher.DecodeBytes(Output); // <-- output has been received here
Cipher.Done; // <-- "processing" of the last block does not affect "Output"
So I wonder, am I missing something if I don't receive data from the "processing" of the last block? Thanks for clarification!
I have to encrypt/decrypt a string on AES 256 CBC, and I'm getting a shorter string compared wit PHP.
PHP Example:
https://gist.github.com/ezegg/8d54c98b8fbdce263409eabaf8afabe6
PHP Output
DB8BRqb2q6BW/HLQYN2pr2n9DTL1Q8kp2lvZi3rogbxjEasiMbgU4q5/vDav+p0O0KWlfMm
NekXN+UkbUiB+s/LNf1MF2EgOQEZoivxgp+UJxsuT5vDIMmQXUkuwkyUE+a7hH5FwaDDY8D
NwW2kowFXeE69AcOMaWnyZ+YplKNEUOzQzLstBxWnJE+aSr0+vQN3knkIIjbT10yfSTV/OQA==
FMX Output.
DB8BRqb2q6BW/HLQYN2pr2n9DTL1Q8kp2lvZi3rogbxjEasiMbgU4q5/vDav+p0O0KWlfMm
NekXN+UkbUiB+s/LNf1MF2EgOQEZoivxgp+UJxsuT5vDIMmQXUkuwkyUE+a7hH5FwaDDY8D
NwW2kowFXeE69AcOMaWnyZ+YplKNEUOzQzLstBxWnJE+aSr0+v9Q21xA==
As you can see, string is "shorter" in Delphi.
here is the test string, Secret key and init vector
SECRET_KEY = "HPo7OLqB4Fkk4E2yGOtwqw8H5fHR9kNx67OR4g4UdlA=";
IV = "p5ldmBPdd/9pjC0bDC/nSg==";
Input String:
{"idServicio":79, "idProducto":209 , "referencia": "40425475190118187271", "montoPago": 9999, "telefono":"1111111111", "horaLocal":"20200401222821"}
Thank you
The literature describes that the initial vector (IV) should not be constant.
I have therefore changed the code so that the IV is also changed each time the key is changed.
I realized this with the help of a hash of the key in truncated length (12).
Then I set OnChange and OnTyping of the editKey.
I hope that I have communicated this correctly.
procedure TFormMain.EditInitVectorChange(Sender: TObject);
var InitV : string; //vom Key wird ein Hash genutzt, um den InitVector zu bestimmen (OnChange und OnTyping von editKey setzen)
begin
InitV := THashSHA2.GetHashString(EditKey.Text, THashSHA2.TSHA2Version.SHA224).ToLower;
EditInitVector.text:=Copy (InitV,0,12);
end;
Hi,
I need to encrypt some strings that are to be verified after with another application.
The other application is in C# and the send me this piece of source code:
public static string encrypt(string value, string key)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
des.Key = ASCIIEncoding.ASCII.GetBytes(key);
des.IV = ASCIIEncoding.ASCII.GetBytes(key);
ICryptoTransform encryptor = des.CreateEncryptor();
byte[] messageBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(value);
byte[] encryptedBytes = encryptor.TransformFinalBlock(messageBytes, 0, messageBytes.Length);
return Convert.ToBase64String(encryptedBytes);
}
I'm having trouble to make the encryptation compatible.
Example:
using: encrypt(“1234568”, "c9FC57w3");
I should have: bVRN+cnpPLvpJkRE+W5+JQ==
Can you help?
Thank you
Hello,
Thanks for the project!
Does this project has any ties with https://github.com/decfpc/DelphiEncryptionCompendium which has the exact same name?
Thanks!
I want to suggest a combination of the following methods:
Background information: I want to encrypt a large file which does not fit into the memory, and I would like to do "Encrypt-then-HMAC". So I need to HMAC the whole file or stream. (Pre-hasing is not a solution, because it is insecure)
Here is the code I wrote (actually copied and modified) and tested.
type
TDECHashExtendedAuthentication = class helper for TDECHashAuthentication
class function HMACFile(const Key: TBytes; const FileName: string;
const OnProgress:TDECProgressEvent = nil): TBytes;
class function HMACStream(const Key: TBytes; const Stream: TStream; Size: Int64;
const OnProgress:TDECProgressEvent = nil): TBytes;
end;
{ TDECHashExtendedAuthentication }
class function TDECHashExtendedAuthentication.HMACFile(const Key: TBytes;
const FileName: string; const OnProgress: TDECProgressEvent): TBytes;
var
fs: TFileStream;
begin
fs := TFileStream.Create(FileName, fmOpenRead);
try
HMACStream(Key, fs, fs.Size, OnProgress);
finally
FreeAndNil(fs);
end;
end;
class function TDECHashExtendedAuthentication.HMACStream(const Key: TBytes;
const Stream: TStream; Size: Int64;
const OnProgress: TDECProgressEvent = nil): TBytes;
const
CONST_UINT_OF_0x36 = $3636363636363636;
CONST_UINT_OF_0x5C = $5C5C5C5C5C5C5C5C;
var
HashInstance: TDECHashAuthentication;
InnerKeyPad, OuterKeyPad: array of Byte;
I, KeyLength, BlockSize, DigestLength: Integer;
begin
// Taken from TDECHashAuthentication.HMAC and changed HashInstance.Calc to HashInstance.CalcStream for the message
HashInstance := TDECHashAuthenticationClass(self).Create;
try
BlockSize := HashInstance.BlockSize; // 64 for sha1, ...
DigestLength := HashInstance.DigestSize;
KeyLength := Length(Key);
SetLength(InnerKeyPad, BlockSize);
SetLength(OuterKeyPad, BlockSize);
I := 0;
if KeyLength > BlockSize then
begin
Result := HashInstance.CalcBytes(Key);
KeyLength := DigestLength;
end
else
Result := Key;
while I <= KeyLength - SizeOf(NativeUInt) do
begin
PNativeUInt(@InnerKeyPad[I])^ := PNativeUInt(@Result[I])^ xor NativeUInt(CONST_UINT_OF_0x36);
PNativeUInt(@OuterKeyPad[I])^ := PNativeUInt(@Result[I])^ xor NativeUInt(CONST_UINT_OF_0x5C);
Inc(I, SizeOf(NativeUInt));
end;
while I < KeyLength do
begin
InnerKeyPad[I] := Result[I] xor $36;
OuterKeyPad[I] := Result[I] xor $5C;
Inc(I);
end;
while I <= BlockSize - SizeOf(NativeUInt) do
begin
PNativeUInt(@InnerKeyPad[I])^ := NativeUInt(CONST_UINT_OF_0x36);
PNativeUInt(@OuterKeyPad[I])^ := NativeUInt(CONST_UINT_OF_0x5C);
Inc(I, SizeOf(NativeUInt));
end;
while I < BlockSize do
begin
InnerKeyPad[I] := $36;
OuterKeyPad[I] := $5C;
Inc(I);
end;
HashInstance.Init;
HashInstance.Calc(InnerKeyPad[0], BlockSize);
if Size > 0 then
TDECHashExtended(HashInstance).CalcStream(Stream, Size, OnProgress, false);
HashInstance.Done;
Result := HashInstance.DigestAsBytes;
HashInstance.Init;
HashInstance.Calc(OuterKeyPad[0], BlockSize);
HashInstance.Calc(Result[0], DigestLength);
HashInstance.Done;
Result := HashInstance.DigestAsBytes;
finally
HashInstance.Free;
end;
end;
Hello,
I was just testing the Cipher_FMX program.
I set the Input format to TFormat_Copy and output to TFormat_Hex
Setup the rest and put 'Hello' into the plain text and press Encrypt. Then press Decrypt and its not correct.
Could be my logic or thinking of course.
In the procedure TFormMain.ButtonDecryptClick(Sender: TObject);
I swapped the following which gets it working.
OutputBuffer := (Cipher as TDECFormattedCipher).DecodeBytes(OutputFormatting.Decode(InputBuffer));
EditPlainText.Text := string(DECUtil.BytesToRawString(InputFormatting.Encode(OutputBuffer)));
// OutputBuffer := (Cipher as TDECFormattedCipher).DecodeBytes(InputFormatting.Decode(InputBuffer));
//
// EditPlainText.Text := string(DECUtil.BytesToRawString(OutputFormatting.Encode(OutputBuffer)));
I have used a key with 18 digits and get an exception afterwards: Keymaterial is too large for use (securityissue).
With a key of 16 characters the program runs without errors.
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Expected and actual behavior
A clear and concise description of what you expected to happen
and what you see happening.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Add any other context about the problem here.
I use Delphi 10.4.2 and I have Oneplus7 android 11
Steps to reproduce the behavior:
Just add DECCiphers in uses list in an activity, compile it in Android 32bit release mode, default settings:
a) run it without debugging from IDE and it hangs on splash screen.
b) run it with debugging from IDE and it gives error: Project .apk raised exception class Bus Error (10) (see image for stack/memory)
c) playing with Compiling options and rebuild it after each change:
i) Turning off optimization, the problem is solved
ii) If "Debug Information" or "Limited Debug information" is selected again the problem is solved.
In debug mode or in both modes of android64, everything is ok
The "exception class Bus Error" is described in the following link as a problem of the compiler for android32 with packed classes:
https://support.tmssoftware.com/t/exception-class-bus-error-when-saving-file/3623
Calling THash_SHA1.PBKDF2 produces incorrect or different results for different key lengths:
THash_SHA1.PBKDF2('PassWord', 'Salt', 1000, 16)
returns
(5, 231, 179, 63, 147, 234, 29, 53, 147, 155, 50, 173, 89, 148, 239, 99).
THash_SHA1.PBKDF2('PassWord', 'Salt', 1000, 32)
returns
(25, 19, 104, 233, 243, 31, 227, 133, 0, 222, 240, 86, 147, 7, 76, 55, 22, 159, 117, 140, 25, 19, 104, 233, 243, 31, 227, 133, 0, 222, 240, 86)
THash_SHA1.PBKDF2('PassWord', 'Salt', 1000, 48)
returns
(25, 19, 104, 233, 243, 31, 227, 133, 0, 222, 240, 86, 147, 7, 76, 55, 22, 159, 117, 140, 25, 19, 104, 233, 243, 31, 227, 133, 0, 222, 240, 86, 147, 7, 76, 55, 22, 159, 117, 140, 159, 45, 208, 2, 26, 124, 20, 230)
My understanding is that the first 16 bytes of the result should be identical in all cases. Unfortunately this is not the case.
Are there plans to support the brypt hash for securing passwords. This has been deemed to be one of the safest ways of hashing them as it requires a Salt to be provided and also is self tuning so the speed remains relatively constant, even when run on faster hardware.
More info at
https://auth0.com/blog/hashing-in-action-understanding-bcrypt/
Would be happy if this only supported Delphi 10.x and above.
As I'm currently writing unit tests for the DECCipherFormats unit I encountered that the DecodeStringToString method for unicode strings (normal string type) is most likely broken.
It produces different output compared to DecodeStringToBytes on the bytewise same input data.
I'll try to investigate further and fix it, but it might need further time.
I try decrypt array of byte, size of array is 70 bytes, data is encrypted with MARS algorithm, although the problem is probably different than the algorithm.
I call DecodeBytes method:
function TDECCipher.DecodeBytes(const Source: TBytes; Format: TDECFormatClass): TBytes;
begin
SetLength(Result, 0);
if Length(Source) > 0 then
begin
Result := ValidFormat(Format).Decode(Source);
DoDecode(@Result[0], @Result[0], Length(Result) * SizeOf(Result[0]));
end;
end;
And this method calls a method from the class implementing the MARS algorithm and I have an exception right on the first line:
procedure TCipher_Mars.DoDecode(Source, Dest: Pointer; Size: Integer);
var
K: PUInt32Array;
I, L, R, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize); << I get this exception because source data size is 70 but BlockSize is 16
In old DEC library version the Decode method looked like this:
procedure TDECCipher.Decode(const Source; var Dest; DataSize: Integer);
begin
CheckState([csInitialized, csDecode, csDone]);
case FMode of
cmECBx: DecodeECBx(@Source, @Dest, DataSize);
cmCBCx: DecodeCBCx(@Source, @Dest, DataSize);
cmCTSx: DecodeCTSx(@Source, @Dest, DataSize);
cmCFB8: DecodeCFB8(@Source, @Dest, DataSize);
cmCFBx: DecodeCFBx(@Source, @Dest, DataSize);
cmOFB8: DecodeOFB8(@Source, @Dest, DataSize);
cmOFBx: DecodeOFBx(@Source, @Dest, DataSize);
cmCFS8: DecodeCFS8(@Source, @Dest, DataSize);
cmCFSx: DecodeCFSx(@Source, @Dest, DataSize);
end;
end;
And each method dependent on the encoding mode had a loop, dividing the data into blocks.
Eg.:
procedure DecodeECBx(S,D: PByteArray; Size: Integer);
var
I: Integer;
begin
if Context.BlockSize = 1 then
begin
DoDecode(S, D, Size);
FState := csDecode;
end else
begin
Dec(Size, FBufferSize);
I := 0;
while I <= Size do
begin
DoDecode(@S[I], @D[I], FBufferSize);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
if Size mod Context.BlockSize = 0 then
begin
DoDecode(@S[I], @D[I], Size);
FState := csDecode;
end else
begin
FState := csPadded;
InvalidMessageLength(Self);
end;
end;
end;
Where is this loop currently implemented?
Describe the solution you'd like
CPU/GPU Accelerating Hashing & Encryption
Additional context
On CPU using SSE/AVX Extensions and GPU using OpenCL/CUDA
Describe the bug
In DEC (6.4.1) when using block cipher, e.g. AES or DES, I encounter range check error exception in DECCipherModes.pas (2022-02-27), TDECCipherModes.EncodeCBCx() when encrypting blocks larger than 32 KiB.
It happens because the block cipher type for Source and Dest is PByteArray.
PByteArray is defined in Delphi RTL System.SysUtils (Delphi 10.2, 10.3) as:
type
...
PByteArray = ^TByteArray;
TByteArray = array[0..32767] of Byte;
To Reproduce
1, Enable range check error in compiler options
2. Call a function like this:
function AESEncryptSomething(): TBytes;
begin
SetLength(SouceTab, 256*1024); // Size >32 KiB
AESCipher:=TCipher_AES.Create;
AESCipher.Init(AESKey, IV, 0); // Key and InitVector
AESCipher.Mode:=cmCBCx;
Result:=AESCipher.EncodeBytes(SourceTab); // Range check error!
FreeAndNil(AESCipher);
end;
Expected and actual behavior
As an user of the DEC lib, your work around method could be to disable range checking for your whole application in the Delphi compiler settings. However that is not a good option.
Alternative work around is in DECCipherModes.pas just after implementation keyword to disable range check for rest of unit. Do:
implementation
{$R-}
To resolve this problem I recommend that DEC lib should rather define and use its own byte data block type, something like:
TDECByteArray = array[0..MaxInt-1] of Byte;
Describe the bug
I used FMX Cipher Demo to use both AES and DES encryptions to make them work with this site : https://www.devglan.com/online-tools/aes-encryption-decryption
The issue comes when you select ECB cipher mode but message length is not a multiple of 8
I already spent a lot of time with other Delphi encryption libraries and found this post years ago explaining ECB needs padding as well
https://stackoverflow.com/questions/55137264/lockbox-3-encrypting-not-matching-online-tool-suspect-padding-or-key-problem
PKCS5PadStringToBytes function described in the post solved my problem, please find below the part of code updated
`
function PKCS5PadStringToBytes(RawData: string; const PadSize: integer): System.SysUtils.TBytes;
var
DataLen: integer;
PKCS5PaddingCount: ShortInt;
begin
result := TEncoding.UTF8.GetBytes(RawData);
DataLen := Length(RawData);
PKCS5PaddingCount := PadSize - DataLen mod PadSize;
if PKCS5PaddingCount = 0 then
PKCS5PaddingCount := PadSize;
Inc(DataLen, PKCS5PaddingCount);
SetLength(result, DataLen);
FillChar(result[DataLen - PKCS5PaddingCount], PKCS5PaddingCount, PKCS5PaddingCount);
end;
procedure TFormMain.ButtonEncryptClick(Sender: TObject);
var
Cipher: TDECCipherModes;
InputFormatting: TDECFormatClass;
OutputFormatting: TDECFormatClass;
InputBuffer: TBytes;
OutputBuffer: TBytes;
begin
if not GetFormatSettings(InputFormatting, OutputFormatting) then
exit;
try
Cipher := GetInitializedCipherInstance;
try
InputBuffer := System.SysUtils.BytesOf(EditPlainText.Text);
if GetSelectedCipherMode = cmECBx then
begin
InputBuffer := PKCS5PadStringToBytes(EditPlainText.Text, 8);
end;
...`
I wonder why you explicitly ignore padding in ECB mode ?
You will find below a screenshot with my fix, matching demo result with the website
Maybe it's a good idea to mark ciphers, that shouldn't be used anymore as deprecated, so developers using these ciphers are warned when they use them.
Describe the bug
Tried to compile my test application for x64 using Delphi 10.4.1 commandline compiler, and it failed with errors:
DECCiphers.pas(977) Error: E2010 Incompatible types: 'PBlowfish' and 'PByteArray'
DECCiphers.pas(1051) Error: E2010 Incompatible types: 'PBlowfish' and 'PByteArray'
DECCiphers.pas(2427) Error: E2010 Incompatible types: 'PUInt32Array' and 'PByteArray'
DECCiphers.pas(4726) Error: E2010 Incompatible types: 'PUInt32Array' and 'PByteArray'
To Reproduce
It can be reproduced straight away from your original sources package
Shark, 3DES, 2DES some time fail to decrypt data in all modes except OFB
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.