#1 2022-05-25 14:57:58

liam1983
Member
Registered: 2021-01-01
Posts: 10

Try to decrypt a string from C#

Hi,

I created the following Base64 string with C#
4XoaSLUowvAbRZl76s053aRzoWrMpxqayzBOk/syjdQ=
With the following settings:
Key Size: 256 bits / 32 bytes
Cipher Mode: CBC
Padding: PKCS#7
Initialization Vector: 16 byte
And the IV is at the beginning of the data.

The content is Hallo and the password was also Hallo.
So I try to do this in Delphi:

procedure TTest.DecryptEigenschaften(cryptedString: string);
var
  AES: TAESCBC;
  sha: TSHA256Digest;
  InBytes, OutBytes: TBytes;
  s: string;
begin
  InBytes := TNetEncoding.Base64.DecodeStringToBytes(cryptedString);
  sha := SHA256Digest(UTF8Encode('Hallo'));
  AES := TAESCBC.Create(sha, 256);
  try

    OutBytes := AES.DecryptPKCS7(InBytes, True);
    s := TNetEncoding.Base64.EncodeBytesToString(OutBytes);
  finally
    FreeAndNil(AES);
  end;
end;

But I got, invalid data. What to do?

Offline

#2 2022-05-25 16:11:05

rvk
Member
Registered: 2022-04-14
Posts: 87

Re: Try to decrypt a string from C#

Could be useful to show the C# code too of how you encrypted this.

How did you pad the key in C#, with spaces? With #0? etc

The problem is that during decryption the last byte (which should contain the padding) is larger than the sizeof(TAESBlock).

Key should also be exactly 32 bytes (or padding to that number should be the same on both ends).

Offline

#3 2022-05-30 06:13:48

liam1983
Member
Registered: 2021-01-01
Posts: 10

Re: Try to decrypt a string from C#

This is the C# code.

 public string Encrypt(string value, string password)
        {
            var rngCryptoServiceProvider = new RNGCryptoServiceProvider();

            // password
            var passwordBytes = Encoding.UTF8.GetBytes(password);

            // iv
            var iv = new byte[16];
            rngCryptoServiceProvider.GetNonZeroBytes(iv);

            // salt erstellen
            var salt = Encoding.UTF8.GetBytes(password);
            var sha1 = HashAlgorithm.Create("SHA1");
            salt = Enumerable.Range(0, Iterations).Aggregate(salt, (current, i) => sha1.ComputeHash(current));


            var passwordDeriveBytes = new Rfc2898DeriveBytes(passwordBytes, salt, Iterations);
            using (var aesManaged = new AesManaged())
            {
                var keyBytes = passwordDeriveBytes.GetBytes(KeySize / 8);

                aesManaged.Mode = CipherMode.CBC;
                aesManaged.Padding = PaddingMode.PKCS7;

                byte[] encrypted;
                using (var encryptor = aesManaged.CreateEncryptor(keyBytes, iv))
                using (var toMemoryStream = new MemoryStream())
                using (var writer = new CryptoStream(toMemoryStream, encryptor, CryptoStreamMode.Write))
                {
                    var valueBytes = Encoding.UTF8.GetBytes(value);

                    writer.Write(valueBytes, 0, valueBytes.Length);
                    writer.FlushFinalBlock();
                    encrypted = new byte[16 + toMemoryStream.Length];
                    iv.CopyTo(encrypted, 0);
                    toMemoryStream.ToArray().CopyTo(encrypted, 16);
                }

                aesManaged.Clear();
                return Convert.ToBase64String(encrypted);
            }
        }

Offline

#4 2022-05-30 07:35:45

igors233
Member
Registered: 2012-09-10
Posts: 233

Re: Try to decrypt a string from C#

You're using SHA1 in C# and SHA256 in Delphi. Try to change C# to same. Note that TAESCBC doesn't support SHA1.

Offline

#5 2022-05-30 08:36:45

rvk
Member
Registered: 2022-04-14
Posts: 87

Re: Try to decrypt a string from C#

You also use Rfc2898DeriveBytes to get a hash of the password.
In Delphi you use the same password as exact key (which is not the same as the passwordDeriveBytes password hash).
https://9to5answer.com/why-do-i-need-to … -key-or-iv

Rfc2898DeriveBytes is an implementation of PBKDF2. What it does is repeatedly hash the user password along with the salt.

You could look at the function PBKDF2_HMAC_SHA256 after you translated the C# to SHA256 (but I'm not sure if they give the exact same result).

You could also just try to use a exact 32 bytes key in your C# code which is the same as in Delphi (without the Rfc2898DeriveBytes step).

Offline

#6 2022-05-30 13:32:07

liam1983
Member
Registered: 2021-01-01
Posts: 10

Re: Try to decrypt a string from C#

rvk wrote:

You also use Rfc2898DeriveBytes to get a hash of the password.
In Delphi you use the same password as exact key (which is not the same as the passwordDeriveBytes password hash).
https://9to5answer.com/why-do-i-need-to … -key-or-iv

Rfc2898DeriveBytes is an implementation of PBKDF2. What it does is repeatedly hash the user password along with the salt.

You could look at the function PBKDF2_HMAC_SHA256 after you translated the C# to SHA256 (but I'm not sure if they give the exact same result).

You could also just try to use a exact 32 bytes key in your C# code which is the same as in Delphi (without the Rfc2898DeriveBytes step).

Thanks! I will try it.

Offline

#7 2022-05-30 14:16:48

liam1983
Member
Registered: 2021-01-01
Posts: 10

Re: Try to decrypt a string from C#

Hi,

so I changed my C# code to

var rngCryptoServiceProvider = new RNGCryptoServiceProvider();

            // iv
            var iv = new byte[16];
            rngCryptoServiceProvider.GetNonZeroBytes(iv);

            var key64 = "TW4YnFfPEhLeehtwdEAZyJYg/zYxeeaDjlhKIifwGKI=";
                           
            using (var aesManaged = new AesManaged())
            {
                var keyBytes = Convert.FromBase64String(key64);

                aesManaged.Mode = CipherMode.CBC;
                aesManaged.Padding = PaddingMode.PKCS7;

                byte[] encrypted;
                using (var encryptor = aesManaged.CreateEncryptor(keyBytes, iv))
                using (var toMemoryStream = new MemoryStream())
                using (var writer = new CryptoStream(toMemoryStream, encryptor, CryptoStreamMode.Write))
                {
                    var valueBytes = Encoding.UTF8.GetBytes(value);

                    writer.Write(valueBytes, 0, valueBytes.Length);
                    writer.FlushFinalBlock();
                    encrypted = new byte[16 + toMemoryStream.Length];
                    iv.CopyTo(encrypted, 0);
                    toMemoryStream.ToArray().CopyTo(encrypted, 16);
                }

                aesManaged.Clear();
                return Convert.ToBase64String(encrypted);
            }

And give the same key and the result (WKaCNKYZpF9tb/CLp8fW/mX4r95OfjztavXhycsgDpA=) to Delphi

procedure TTest.DecryptEigenschaften(cryptedString: string);
var
  AES: TAESCBC;
  sha: TSHA256Digest;
  InBytes, OutBytes, Key: TBytes;
  s: string;
begin
  InBytes := TNetEncoding.Base64.DecodeStringToBytes(cryptedString);
//  sha := TNetEncoding.Base64.DecodeStringToBytes(cryptedString);
  Key := TNetEncoding.Base64.DecodeStringToBytes('TW4YnFfPEhLeehtwdEAZyJYg/zYxeeaDjlhKIifwGKI=');
  AES := TAESCBC.Create(key, 256);
  try

    OutBytes := AES.DecryptPKCS7(InBytes, True);
    s := TNetEncoding.Base64.EncodeBytesToString(OutBytes);
  finally
    FreeAndNil(AES);
  end;
end;
But still get the same error.

Offline

#8 2022-05-30 15:04:29

igors233
Member
Registered: 2012-09-10
Posts: 233

Re: Try to decrypt a string from C#

This is a simple Enc/Decrypt for AESCBC, try to replicate it in C#.

var
  Temp: RawByteString;
begin
  Temp := BinToBase64(TAESCBC.SimpleEncrypt('Lorem ipsum dolor sit amet, con', '123456', True, True));
  WriteLn(Temp);
  Temp := TAESCBC.SimpleEncrypt(Base64ToBin(Temp), '123456', False, True, True);
  WriteLn(Temp);
end;

Offline

#9 2022-05-31 08:23:22

rvk
Member
Registered: 2022-04-14
Posts: 87

Re: Try to decrypt a string from C#

I can confirm the C# code is correct (or at least I can decrypt it in FPC/DCPcrypt2).

uses DCPrijndael, DCPcrypt2, base64;

function myDecryptCBC: ansistring;
var
  Cipher: TDCP_rijndael;
  Data, DataString, Key, IV: ansistring;
begin
  Data := DecodeStringBase64('WKaCNKYZpF9tb/CLp8fW/mX4r95OfjztavXhycsgDpA=');
  Key := DecodeStringBase64('TW4YnFfPEhLeehtwdEAZyJYg/zYxeeaDjlhKIifwGKI=');
  Assert(Length(Key) = 32);
  IV := Copy(Data, 1, 16);
  DataString := Copy(Data, 17);
  Cipher := TDCP_rijndael.Create(nil);
  Cipher.CipherMode := cmCBC;
  Cipher.Init(Key[1], Length(Key) * 8, @IV[1]);
  Cipher.DecryptCBC(DataString[1], DataString[1], Length(DataString));
  // PKCS7, last char is #11 which results in 16 - 11 = 5, length of Hallo
  DataString := Copy(DataString, 1, Length(DataString) - Ord(DataString[Length(DataString)]));
  Result := DataString;
  Cipher.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: ansistring;
begin
  S := myDecryptCBC;
  Memo1.Lines.Add(S);
end;

Gives result

Hallo

I'm not sure why TAESCBC gives another result.

Offline

#10 2022-05-31 09:04:51

rvk
Member
Registered: 2022-04-14
Posts: 87

Re: Try to decrypt a string from C#

Fixed it. Here the solution for Delphi/TAESCBC.
(pass Key[0] to Create and no need to base-encode the result)

procedure TForm1.Button1Click(Sender: TObject);
const
  cryptedString: string = 'WKaCNKYZpF9tb/CLp8fW/mX4r95OfjztavXhycsgDpA=';
  keystring: string = 'TW4YnFfPEhLeehtwdEAZyJYg/zYxeeaDjlhKIifwGKI=';
var
  AES: TAESCBC;
  InBytes, OutBytes, Key: TBytes;
  S: ANSIstring;
begin
  InBytes := TNetEncoding.Base64.DecodeStringToBytes(cryptedString);
  Key := TNetEncoding.Base64.DecodeStringToBytes(keystring);
  AES := TAESCBC.Create(Key[0], 256); // Pass the string, not the pointer to string
  try
    OutBytes := AES.DecryptPKCS7(InBytes, True);
    S := TEncoding.ANSI.GetString(OutBytes); // No need to base64 encode again
    Memo1.Lines.Add(S);
  finally
      FreeAndNil(AES);
  end;
end;

Result:

Hallo

Last edited by rvk (2022-05-31 09:05:28)

Offline

Board footer

Powered by FluxBB