Tool B4XEncryption : Decrypt from Delphi

Use DCPcrypt lib from https://sourceforge.net/p/dcpcrypt/code/HEAD/tree/
I took code from: http://keit.co/p/dcpcrypt-hmac-rfc2104/

The code:
B4X:
uses DCPcrypt2, DCPsha1,  DCPblockciphers, DCPrijndael;

function RPad(x: ansistring; c: AnsiChar; s: Integer): ansistring;          var i: Integer;
begin Result:=x; if Length(x)<s then for i:=1 to s-Length(x) do Result:=Result+c; end;

function XorBlock(s, x: ansistring): ansistring; inline;        var i: Integer;
begin SetLength(Result,Length(s)); for i:=1 to Length(s) do Result[i]:=AnsiChar(Byte(s[i]) xor Byte(x[i])); end;

function CalcDigest(text: ansistring): ansistring;      var x:TDCP_sha1;
begin x:=TDCP_sha1.Create(nil); try  x.Init; x.UpdateStr(text);
SetLength(Result,x.GetHashSize div 8); x.Final(Result[1]); finally x.Free; end; end;

function CalcHMAC(mess,key: ansistring): ansistring;
const blocksize = 64;
begin  // Definition RFC 2104
if Length(key) > blocksize then key:=CalcDigest(key); key:=RPad(key,#0,blocksize);
Result:=CalcDigest(XorBlock(key,RPad('',#$36,blocksize))+mess);
Result:=CalcDigest(XorBlock(key,RPad('',#$5c,blocksize))+result); end;

function PBKDF1(pass, salt: ansistring; count: Integer): ansistring;
var i: Integer;
begin Result:=pass+salt; for i:=0 to count-1 do Result:=CalcDigest(Result); end;

function PBKDF2(pass, salt: ansistring; count, kLen: Integer; hash: TDCP_sha1): ansistring;
  function IntX(i: Integer): ansistring; inline;
  begin Result:=ansiChar(i shr 24)+ansiChar(i shr 16)+ansiChar(i shr 8)+ansiChar(i); end;
var D,I,J:Integer; T,F,U:ansistring;
begin T:=''; D:=Ceil(kLen/(hash.GetHashSize div 8)); for i:=1 to D do begin
F:=CalcHMAC(salt+IntX(i),pass); U:=F; for j:=2 to count do begin
U:=CalcHMAC(U,pass); F:=XorBlock(F,U); end; T:=T+F; end; Result:=Copy(T,1,kLen); end;

function encrypt(const data, password: string): string;
var n,i,m:integer; salt,iv,key,dat:rawbytestring; h:TDCP_sha1; ra:TDCP_rijndael; p:pwidechar;
begin setlength(iv,16); for n:=1 to 16 do iv[n]:=ansichar(Random(256));
setlength(salt,8); for n:=1 to 8 do salt[n]:=ansichar(random(256)); result:='';
dat:=UTF8Encode(data); i:=length(dat); m:=16-i mod 16; if m=0 then m:=16; i:=i+m;
setlength(dat,i); for n:=i-m+1 to i do dat[n]:=ansichar(m);
h:=TDCP_sha1.Create(nil); ra:=TDCP_rijndael.Create(nil); try
key:=UTF8Encode(password); h.Init; key:=PBKDF2(key,salt,1024,16,h);
ra.Init(key[1],128,@IV[1]); ra.encryptCBC(dat[1],dat[1],i); finally ra.Free; h.Free; end;
setlength(result,i+48); p:=@result[1]; BinToHex(@salt[1],p,8); inc(p,16);
BinToHex(@iv[1],p,16); inc(p,32); BinToHex(@dat[1],p,i); end;

function decrypt(const data,password: string): string;
var n,i:integer; h:TDCP_sha1; ra:TDCP_rijndael; dat,salt,iv,key:rawbytestring;
begin i:=(length(data) div 2)-24; setlength(dat,i); setlength(iv,16); setlength(salt,8);
result:=LowerCase(data); HexToBin(pwidechar(result),@salt[1],8);
system.Delete(result,1,16); HexToBin(pwidechar(result),@iv[1],16);
system.Delete(result,1,32); hextobin(pwidechar(result),@dat[1],i);
h:=TDCP_sha1.Create(nil); h.Init; ra:=TDCP_rijndael.Create(nil); try
key:=UTF8Encode(password); key:=PBKDF2(key,salt,1024,16,h); ra.Init(key[1],128,@IV[1]);
ra.DecryptCBC(dat[1],dat[1],i); finally ra.Free; h.Free; end;
if byte(dat[i])>16 then begin result:=''; exit; end;
dec(i,byte(dat[i])); setlength(dat,i); result:=UTF8Decode(dat); end;

The above updated, with encrypt-descrypt routines
 
Last edited:

dcoun

Member
Licensed User
It was late in the night, when I posted my first results. Today, I had the time to rewrite it and test it. Padding was added using PKCS7 standard. Passwords can be in any language. Tested in B4J and Delphi 10.1 and works ok. No extra dll needed. Lazarus is supported. modules for apache can use it.
Feel free to report any problem....
 
Last edited:

dcoun

Member
Licensed User
The following uses TMS Cryptography Pack (https://www.tmssoftware.com/site/tmscrypto.asp) and works in all platforms

B4X Encryption for Delphi:
unit Unit1;

interface
uses system.classes, system.SysUtils;

type TC4D=class
   type Pbytes=^Tbytes;
 private
   class function PBKDF2(const pass, salt: tbytes; const count, kLen: Integer): tbytes;
   class function CalcDigest(const text: tbytes): tbytes;
   class function CalcHMAC(const mess:tbytes; const key: tbytes):tbytes;
   class function RPad(const x:tbytes; const c:byte; const s:Integer):tbytes;
   class function XorBlock(const s, x: tbytes): tbytes;
   class procedure mkpass(const password: utf8string; co,k:pbytes);
 public
   class function encrypt(const data:tbytes; const password: utf8string): tbytes;
   class function decrypt(const data:tbytes; password: utf8string):tbytes;
end;

implementation
uses System.Hash, AESObj, miscobj;

{ TE4D }

class procedure TC4D.mkpass(const password: utf8string; co, k: Pbytes);
var
  key: Tbytes;
  n, i: Integer;
  p: RawByteString;
begin
  p := RawByteString(password);
  setlength(key, length(p));
  i := 0;
  for n := low(p) to high(p) do
  begin
    key[i] := byte(password[n]);
    inc(i);
  end;
  if length(co^) <> 8 then
  begin
    setlength(co^, 8);
    for n := 0 to 7 do
      co^[n] := random(256);
  end;
  setlength(k^, 16);
  k^ := PBKDF2(key, co^, 1024, 16);
end;

class function TC4D.RPad(const x: Tbytes; const c: byte;
  const s: Integer): Tbytes;
var
  i, n: Integer;
begin
  result := x;
  n := length(x);
  if n >= s then
    exit;
  setlength(result, s);
  for i := n to s - 1 do
    result[i] := c;
end;

class function TC4D.XorBlock(const s, x: Tbytes): Tbytes;
var
  i: Integer;
begin
  setlength(result, length(s));
  for i := 0 to length(s) - 1 do
    result[i] := s[i] xor x[i];
end;

class function TC4D.CalcDigest(const text: Tbytes): Tbytes;
var
  v: THashSHA1;
begin
  v.Reset;
  v.Update(text);
  result := v.HashAsBytes;
end;

class function TC4D.CalcHMAC(const mess: Tbytes; const key: Tbytes): Tbytes;
var
  mkey, t: Tbytes;
const
  blocksize = 64;
begin
  if length(key) > blocksize then
    mkey := CalcDigest(key)
  else
    mkey := key;
  setlength(t, 0);
  mkey := RPad(mkey, 0, blocksize);
  result := XorBlock(mkey, RPad(t, $36, blocksize));
  system.Insert(mess, result, length(result));
  result := CalcDigest(result); // Definition RFC 2104
  system.Insert(XorBlock(mkey, RPad(t, $5C, blocksize)), result, 0);
  result := CalcDigest(result);
end;

class function TC4D.PBKDF2(const pass, salt: Tbytes;
  const count, kLen: Integer): Tbytes;
var
  J, i: Integer;
  u, f, bsalt: Tbytes;
begin
  setlength(result, 0);
  i := length(salt);
  bsalt := salt;
  setlength(bsalt, i + 4);
  bsalt[i] := 0;
  bsalt[i + 1] := 0;
  bsalt[i + 2] := 0;
  bsalt[i + 3] := 1;
  f := CalcHMAC(bsalt, pass);
  u := f;
  for J := 2 to count do
  begin
    u := CalcHMAC(u, pass);
    f := XorBlock(f, u);
  end;
  system.Insert(f, result, length(result));
  setlength(result, kLen);
end;

class function TC4D.encrypt(const data: Tbytes;
  const password: utf8string): Tbytes;
var
  key, salt, kk: Tbytes;
  cif: TAESEncryption;
  n, m: Integer;
  i: cardinal;
  si, so: tmemorystream;
  cov: tconvert;
begin
  result := nil;
  i := length(data);
  if (i = 0) or (length(password) < 8) then
    exit;
  try
    m := 16 - (i mod 16);
    if m = 0 then
      m := 16;
    setlength(key, m);
    for n := 0 to m - 1 do
      key[n] := m;
    si := tmemorystream.Create;
    so := tmemorystream.Create;
    try
      si.Write(data, i);
      si.Write(key, m);
      inc(i, m);
      kk := nil;
      mkpass(password, @kk, @key);
      setlength(salt, 16);
      for n := 0 to 15 do
        salt[n] := random(256);
      cov := tconvert.Create;
      cif := TAESEncryption.Create(kl128, cov.tbytestostring(key), atCBC,
        nopadding, raw, noUni, cov.tbytestostring(salt));
      try
        key := nil;
        cif.EncryptStream(si, so);
        if so.Size = 0 then
          exit;
      finally
        cif.Free;
        cov.Free;
      end;
      si.Clear;
      so.Position := 0;
      setlength(result, i + 24);
      move(kk[0], result[0], 8);
      move(salt[0], result[8], 16);
      so.Read(result[24], i);
    finally
      si.Free;
      so.Free;
    end;
  except
    result := nil;
  end;
end;

class function TC4D.decrypt(const data: Tbytes; password: utf8string): Tbytes;
var
  cif: TAESEncryption;
  key, salt: Tbytes;
  i: cardinal;
  si, so: tmemorystream;
  cov: tconvert;
begin
  result := nil;
  if (length(data) < 25) or (length(password) < 8) then
    exit;
  try
    setlength(salt, 8);
    move(data[0], salt[0], 8);
    mkpass(password, @salt, @key);
    setlength(salt, 16);
    move(data[8], salt[0], 16);
    si := tmemorystream.Create;
    so := tmemorystream.Create;
    try
      cov := tconvert.Create;
      cif := TAESEncryption.Create(kl128, cov.tbytestostring(key), atCBC,
        nopadding, raw, noUni, cov.tbytestostring(salt));
      try
        salt := nil;
        key := nil;
        si.Write(data[24], length(data) - 24);
        if cif.DecryptStream(si, so) <> 0 then
          exit;
      finally
        cif.Free;
        cov.Free;
      end;
      si.Clear;
      i := so.Size;
      setlength(result, i);
      so.Position := 0;
      so.Read(result[0], i);
    finally
      si.Free;
      so.Free;
    end;
    if result[i - 1] > 16 then
    begin
      result := nil;
      exit;
    end;
    dec(i, result[i - 1]);
    setlength(result, i);
  except
    result := nil;
  end;
end;

end.
 
Top