You are not logged in.
Hello,
I am using Delphi 10.2, mORMot commit version 1.18.3599
I do not know if this is something known.
I have switched my target platform to 64bit Windows for one of my applications. There is no code change at all. That 64bit application could not decrypt information crypt with Win32 executable using same mORMot version. Everything is normal if I switch back to Win32 platform.
My code for decrypt is as follows:
function DecryptItAES(const s: string; const AKey: string): string;
var
Key: TSHA256Digest;
Aes: TAESCFB;
_s: RawByteString;
begin
Result := EmptyStr;
SynCommons.HexToBin(Pointer(SHA256(StringToUTF8(AKey))), @Key, 32);
Aes := TAESCFB.Create(Key, 256);
try
_s := StringToUTF8(s);
_s := Aes.DecryptPKCS7(Base64ToBin(_s), True);
Result := UTF8ToString(_s);
finally
Aes.Free();
end;
end;
There is no exception raising at all. It is simply decrypt content is not that it should be.
I appreciate any help.
Thanks & regards,
Ertan
Last edited by ertank (2017-12-12 16:53:59)
Offline
Did you try with the latest mORMot revision (current is 1.18.4074)?
BTW the following code line does not make much sense:
SynCommons.HexToBin(Pointer(SHA256(StringToUTF8(AKey))), @Key, 32);
You may use
Key := SHA256Digest(StringToUTF8(AKey));
directly.
Offline
Just tried with 1.18.4071 revision.
That revision raise an exception saying "TAESCFB.DecryptPKCS7: Invalid Input" when Win64 executable.
Using same revision and Win32 executable everything works fine.
Offline
I tested with Revision 1.18.4080. Same problem continues. Working fine with 32Bit executable. Different decrypt result for 64bit executable using same code and inputs. Please check if you can reproduce using below information.
Delphi version: Embarcadero® RAD Studio 10.2 Version 25.0.26309.314
Decrypt text should be small letter "a"
const
KeyPC : Array of Char = [#00, #101, #02, #03, #40, #05, #106, #07,
#08, #09, #07, #100, #110, #201, #117, #45,
#10, #11, #12, #13, #140, #150, #160, #170,
#13, #1, #17, #130, #40, #16, #106, #70,
#180, #190, #174, #200, #0, #1, #11, #15,
#80, #91, #72, #130, #101, #111, #107, #45];
implementation
uses
SynCommons,
SynCrypto;
function DecryptItAES(const s, AKey: string; out Value: string): Boolean;
var
Key: TSHA256Digest;
Aes: TAESCFB;
Utf8String: RawByteString;
begin
if s = EmptyStr then Exit(False);
//SynCommons.HexToBin(Pointer(SHA256(StringToUTF8(aKey))), @key, 32);
Key := SHA256Digest(StringToUTF8(AKey));
Aes := TAESCFB.Create(Key, 256);
try
Utf8String := StringToUTF8(s);
try
Utf8String := Aes.DecryptPKCS7(Base64ToBin(Utf8String), True);
except
on E: Exception do
begin
ShowMessage(E.Message);
Value := EmptyStr;
Exit(False);
end;
end;
Value := UTF8ToString(Utf8String);
finally
Aes.Free();
end;
Result := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DecryptItAES('oWN2TRhEkb4sJ8IrfqQSm+9qhW5u+xty7qbigw9yk4A=', string(KeyPC), PlainText);
Memo1.Lines.Add('Plain: ' + QuotedStr(PlainText));
end;
BTW, I cannot debug 64bit applications. Couldn't find what problem is with debugging 64bit executable. Execution do not stop at break points even I have compiler and linker debugging information set on.
However, when I try to display exception on the screen I see that there is indeed an exception raised and it is saying:
TAESCFB.DecryptPKCS7: Invalid Input
No such exception in 32bit executable and result is displayed just fine.
Last edited by ertank (2017-12-16 09:38:29)
Offline
Are you using the 10.2 with the update 1?
There was a big bug in the Delphi compiler, for plain 10.2, with x64.
See http://blog.synopse.info/post/2017/03/2 … C64-broken
Anyway, I have included tests vectors to the regression unit, so that we may identify any problem for a specific platform.
I found not problem with Delphi 5, Delphi 6, Delphi 7, Delphi 2007, Delphi XE4 32, Delphi XE6 32/64, Delphi XE7 32/64, FPC Win32/Win64/LinuxX86/LinuxX64.
But I don't have Delphi 10.2 at hand (no licence any more, since I changed my daily job to switch into a FPC-powered startup).
See https://synopse.info/fossil/info/004fedca24
So I'm afraid there may be something wrong in your test code.
Offline
I am using plain Delphi 10.2 with April hotfix applied.
Thanks for additional regression tests.
I am not sure it is the test code having something wrong. I am not changing any code but target platform. Win32 it works and Win64 it does not.
I will wait for a while with the hope that someone in the forum who has Delphi 10.2 (plain or update 1, 2) to test above code example just to be sure.
Both update 1 and update 2 has their own issues and I simply do not want to install neither at the moment.
I might prepare a virtual machine to test with update 1 or update 2 if I can find the time to test the code.
Offline
I just tested same code on Delphi 10.2.2
I got exception on 64bit executable where I have correct result on 32bit executable.
I also got exception encrypt text on 64bit system and trying to decrypt it in 32bit system.
If I encrypt using 64bit executable, it can decrypt that information on 64bit system.
If I encrypt using 32bit executable, it can decrypt that information on 32bit system.
It seems encrypt information is not 32bit <-> 64bit exchangeable. At least on Windows platforms.
Encryption code I used is:
function EncryptItAES(const s, aKey: string; out Value: string): Boolean;
var
Key: TSHA256Digest;
Aes: TAESCFB;
Utf8String: RawByteString;
begin
if s = EmptyStr then Exit(False);
//SynCommons.HexToBin(Pointer(SHA256(StringToUTF8(aKey))), @key, 32);
Key := SHA256Digest(StringToUTF8(AKey));
Aes := TAESCFB.Create(key, 256);
try
Utf8String := StringToUTF8(s);
try
Utf8String := BinToBase64(Aes.EncryptPKCS7(Utf8String, True));
except
Exit(False);
end;
Value := UTF8ToString(Utf8String);
finally
Aes.Free();
end;
Result := True;
end;
Last edited by ertank (2017-12-17 11:29:00)
Offline
ertank
Bug in this expression in your code: string(KeyPC)
To get Key as a string, use this code:
function GetKey: string;
const
KeyPC: array of Char = [
#00, #101, #02, #03, #40, #05, #106, #07,
#08, #09, #07, #100, #110, #201, #117, #45,
#10, #11, #12, #13, #140, #150, #160, #170,
#13, #1, #17, #130, #40, #16, #106, #70,
#180, #190, #174, #200, #0, #1, #11, #15,
#80, #91, #72, #130, #101, #111, #107, #45
];
var
I: Integer;
begin
SetLength(Result, Length(KeyPC));
for I := 0 to Length(KeyPC) - 1 do begin
Result[I+1] := KeyPC[I];
end;
end;
Offline
Or just
SetString(KeyStr, @KeyPC, SizeOf(KeyPC));
But it is obvious that how the key is constructed in the code is somewhat confusing and wrong.
Using "array of char" with 8-bit values sounds plain wrong.
Use "array of bytes", or bintobase64/bintohex, and THash128 or THash256 for key storage.
Offline
Yes, it is my mistake. Sorry for all the fuss.
Below is the current code which is working in both 32bit and 64bit platforms. Encrypt text in one platform can be decrypt in another platform just fine.
unit Unit1;
interface
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
KeyPC : Array of Byte = [00, 101, 02, 03, 40, 05, 106, 07,
08, 09, 07, 100, 110, 201, 117, 45,
10, 11, 12, 13, 140, 150, 160, 170,
13, 1, 17, 130, 40, 16, 106, 70,
180, 190, 174, 200, 0, 1, 11, 15,
80, 91, 72, 130, 101, 111, 107, 45];
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
SynCommons,
SynCrypto;
function DecryptItAES(const s: string; AKey: Array of Byte; out Value: string): Boolean;
var
Key: TSHA256Digest;
Aes: TAESCFB;
Utf8Str: RawByteString;
begin
if s = EmptyStr then Exit(False);
Key := SHA256Digest(Pointer(@AKey), SizeOf(AKey));
Aes := TAESCFB.Create(Key, 256);
try
Utf8Str := StringToUTF8(s);
try
Utf8Str := Aes.DecryptPKCS7(Base64ToBin(Utf8Str), True);
except
Value := EmptyStr;
Exit(False);
end;
Value := UTF8ToString(Utf8Str);
finally
Aes.Free();
end;
Result := True;
end;
function EncryptItAES(const s: string; aKey: Array of Byte; out Value: string): Boolean;
var
Key: TSHA256Digest;
Aes: TAESCFB;
Utf8Str: RawByteString;
begin
if s = EmptyStr then Exit(False);
Key := SHA256Digest(Pointer(@AKey), SizeOf(AKey));
Aes := TAESCFB.Create(Key, 256);
try
Utf8Str := StringToUTF8(s);
try
Utf8Str := BinToBase64(Aes.EncryptPKCS7(Utf8Str, True));
except
Exit(False);
end;
Value := UTF8ToString(Utf8Str);
finally
Aes.Free();
end;
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
TempString: string;
begin
EncryptItAES(Edit1.Text, KeyPC, TempString);
Memo1.Lines.Add(EmptyStr);
Memo1.Lines.Add(TempString);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
TempString: string;
begin
TempString := EmptyStr;
DecryptItAES(Edit1.Text, KeyPC, TempString);
Memo1.Lines.Add('Plain: ' + QuotedStr(TempString));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear();
end;
end.
@zed appreciate you pointing me my bug.
@ab appreciate you correct my basic definition type for KeyPC
That is a good lesson learned for me as I now need to update quite some applications running in different locations.
Regards,
Ertan
Offline
I actually checked it and it returns 48 and not the size of the pointer. That is same for 32bit and 64bit.
My usage is very similar to below code:
const
Test: Array of Byte = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
procedure TestMe(const Key: array of Byte);
begin
ShowMessage('TestMe: ' + IntToStr(SizeOf(Key))); // Here you get 10
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage(IntToStr(SizeOf(Test))); // Here you get 4
TestMe(Test);
end;
Last edited by ertank (2017-12-18 06:15:48)
Offline
This is something new in pascal then...
When Embarcadero implemented dynamic arrays initialization, they broke the previous behavior, existing since the introduction of dynamic arrays, in 1998:
var
Test: Array of Byte;
begin
writeln(SizeOf(Test)); // Here you get 4 (pointer size) since Delphi 4
IMHO that sizeof(Test) returns the length of a dynamic array, and not the pointer size of the dynamic array variable, is a bug of the current Delphi compiler.
Embarcadero seems to like breaking backward compatibility.
Anyway, using "array of byte" for a constant array is IMHO just confusing, slower, and not convenient.
The propery way is to write:
const
Test: array[0..9] of byte = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Then use sizeof(Test).
This is safe, efficient, and clean.
The fact that you need to specify the array length is a feature: you are sure that your constant array has the specified number of items, not more, not less.
Offline
@ab seems that open array behave in different way than dynamic array
procedure TestMe(const Key: TArray<Byte>);
works as expected.
best regards,
Maciej Izak
Offline