Xor-el / HashLib4Pascal

Hashing for Modern Object Pascal
MIT License
218 stars 79 forks source link

Help for Key Derivation Functions "PBKDF2" in delphi #27

Closed Noobaxx closed 1 year ago

Noobaxx commented 1 year ago

Hi,

I'm having trouble using your library. Can you help me?

I'd like create a key Derivation Functions "PBKDF2" like I do in .net core.

This is what I do in .net core

public static string HashUsingPbkdf2(string password, byte[] salt)
{
  byte[] derivedKey = KeyDerivation.Pbkdf2(password, salt, KeyDerivationPrf.HMACSHA256, iterationCount: 100000, 32);

  return Convert.ToBase64String(derivedKey);
 }

The "salt" is generated by RandomNumberGenerator.GetBytes(32); And is saved in the db in Base64 : Convert.ToBase64String(salt). When I need to retrieve it from the db and convert it to "byte[]", I useConvert.FromBase64String(StringSalt).

This is what I do with the library :

function TForm1.PBKDF2(Password: string; Salt: string): string;
var
  PBKDF2 : IPBKDF2_HMAC;
  PassBytes, SaltBytes, ResultBytes: TBytes;
  HashInstance : IHash;
  HMACInstance: IHMAC;
begin

  PassBytes := TBase64Encoding.Base64.DecodeStringToBytes(Password);
  SaltBytes := TBase64Encoding.Base64.DecodeStringToBytes(Salt);

  HashInstance := THashFactory.TCrypto.CreateSHA2_256();
  HMACInstance := THashFactory.THMAC.CreateHMAC(HashInstance);

  PBKDF2 := TKDF.TPBKDF2_HMAC.CreatePBKDF2_HMAC(HMACInstance, PassBytes, SaltBytes, 100000);

  ResultBytes := PBKDF2.GetBytes(32);

  Result := BytesToBase64String(ResultBytes);
end;

But when I try to do it with the same "password" and "salt" I don't get the same result.

Can you show me how to do it in Delphi?

Thank you in advance for your support

Xor-el commented 1 year ago

Hello @Noobaxx apologies for the late response, just seeing this issue now.

there were a couple of issues with your original code.

you can find the C# code below and the updated Delphi one that produces same result as the C# one.

// See https://aka.ms/new-console-template for more information
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

static string HashUsingPbkdf2(string password, byte[] salt)
{
    byte[] derivedKey = KeyDerivation.Pbkdf2(password, salt, KeyDerivationPrf.HMACSHA256, iterationCount: 100000, 32);

    return Convert.ToBase64String(derivedKey);
}

var salt = new byte[] { 1, 2, 3, 4, 5 };
var saltAsBase64String = Convert.ToBase64String(salt);
var saltStringAsBytes = Convert.FromBase64String(saltAsBase64String);

Console.WriteLine(HashUsingPbkdf2("1, 2, 3, 4, 5", saltStringAsBytes));

Console.ReadLine();
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  HlpHashFactory,
  HlpIHash,
  HlpIHashInfo,
  System.SysUtils,
  System.NetEncoding;

function HashUsingPbkdf2(Password: string; Salt: TBytes): string;

var
  PBKDF2: IPBKDF2_HMAC;
  PassBytes, derivedKey: TBytes;
  HashInstance: IHash;

begin
  PassBytes := TEncoding.UTF8.GetBytes(Password);

  HashInstance := THashFactory.TCrypto.CreateSHA2_256();

  PBKDF2 := TKDF.TPBKDF2_HMAC.CreatePBKDF2_HMAC(HashInstance, PassBytes,
    Salt, 100000);

  derivedKey := PBKDF2.GetBytes(32);

  Result := TBase64Encoding.Base64.EncodeBytesToString(derivedKey);
end;

begin
var
 salt, saltStringAsBytes: TBytes;
 var
 saltAsBase64String: string;
  try
    { TODO -oUser -cConsole Main : Insert code here }

    salt := TBytes.Create(1, 2, 3, 4, 5);

    saltAsBase64String := TBase64Encoding.Base64.EncodeBytesToString(salt);

    saltStringAsBytes := TBase64Encoding.Base64.DecodeStringToBytes(saltAsBase64String);

    Writeln(saltAsBase64String);

    Writeln(HashUsingPbkdf2('1, 2, 3, 4, 5', saltStringAsBytes));
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.
Noobaxx commented 1 year ago

Thank you very much.

I now understand my mistakes