Search code examples
androiddelphibcryptdelphi-xe8

Multi-device Bcrypt library for delphi XE8


I was able to find two Bcrypt libraries that can be compiled for windows but I am struggling to compile them for Android in Delphi XE8.

The first one is https://github.com/chinshou/bcrypt-for-delphi which doesn't require any modifications to be compiled for Windows.

For the second one https://github.com/PonyPC/BCrypt-for-delphi-lazarus-fpc I had to make some minor adjustments in the checkPassword function to get the same result since it was FreePascal specific:

function checkPassword(const Str: string; const Hash: ansistring): boolean;
var
  RegexObj: TRegEx;
  match   : TMatch;
  Salt    : String;
begin
  RegexObj := TRegEx.Create('^\$2a\$10\$([\./0-9A-Za-z]{22})',[roIgnoreCase]);
  match := RegexObj.Match(Hash);
  if match.Success then
  begin
    Salt := Copy(match.Value,8,22);
    Result := HashPassword(Str, Salt) = Hash;
  end
  else
  begin
    Result := False;
  end;
end;

After changing the platform from Win to Android the first one shows a lot of errors since it depends on ComObj, Windows and ActiveX. The second one after replacing RegExpr with RegularExpressions and Types shows only conflicts that results from changes in the String variable. The code uses AnsiString, AnsiChar which I cannot just replace with String and Char since it affects the hashing function.

What am I missing? what other modifications should I do to replace the obsolete AnsiString and AnsiChar declarations, allowing the code to be compiled for Android?


Solution

  • The String declaration problem with the second library was caused by the move command in the HashPassword function

    Move(password[1], key[0], Length(password));
    

    since the size of the password variable changed after replacing the declaration from AnsiString to String. Replacing this with a simple for loop and Ord function fixes the problem although there is probably a more elegant way of doing it.

    function HashPassword(const Str: string; const salt: string): string;
    var
      password: String ;
      key, saltBytes, Hash: TBytes;
      i: Integer;
    begin
      password := AnsiToUtf8(str);
    
      SetLength(key, Length(password) + 1);
      for i := 0 to length(password)-1 do
        key[i]:=ord(password[i+1]);
    
      key[high(key)] := 0;
      saltBytes := BsdBase64Decode(salt);
      Hash := CryptRaw(key, saltBytes);
      Result := FormatPasswordHashForBsd(saltBytes, Hash);
    end;
    

    To summarize, the conversion of the second library to an Android compatible code requires the following changes:

    • modifying the regular expression code in the checkPassword function according to the code posted in the question

    • altering the uses section by replacing "RegExpr" with "RegularExpressions, Types"

    • replacing all declarations from AnsiString to String and AnsiChar to Char

    • modifying the HashPassword function as shown above