JackTrapper / argon2-for-delphi

Argon2 password hashing algorithm
The Unlicense
23 stars 9 forks source link

TArgon2.DeriveBytes always returns an array of zeros no matter what passphrase is supplied #3

Open mbtaylor1982 opened 6 years ago

mbtaylor1982 commented 6 years ago

I tested using this code and I always get the same digest in the hash string.

  Hash := TArgon2.HashPassword(Pwd);
  Matched := TArgon2.CheckPassword(Pwd, Hash, Rehash);

the check password function is returning true with the hash strings.

Maybe I'm doing something wrong, i'm not sure

password:

$Argon2id $v=19 $m=131072,t=10000,p=1 $l9yGr4S9jB7D1mZhNLHYWQ== $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

password1:

$Argon2id $v=19 $m=131072,t=10000,p=1 $l2UP21fItrhdXTlnkI2+tQ== $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

password2:

$Argon2id $v=19 $m=131072,t=10000,p=1 $cVH50MP3v87ngjRAKUpqHA== $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

mbtaylor1982 commented 6 years ago

I think this is the problem

TArgon2.GetBytes Aprox line 750

    SetLength(Result, DesiredNumberOfBytes);
    FillChar(Result[0], DesiredNumberOfBytes, 0);

looks like it will always return an array of zeros!

JackTrapper commented 6 years ago

The real problem is that this implementation is nowhere near working, because neither the RFC, nor the white-papers, nor the reference implementations, explain how the algorithm works. Without being able to decipher the algorithm, i have no hope of implementing it.

Hopefully others can decipher the god-awful mess that the different RFC's are, and complete the implementation.

Because they are so badly written, i want to choke his tongue out.

mbtaylor1982 commented 6 years ago

I'm willing to give it a shot if you can let me know where to start looking

mbtaylor1982 commented 6 years ago

Also please add a comment to the home page to say the implementation is not finished or working

JackTrapper commented 6 years ago

I've committed everything i was behind on.

There's five main pieces that make up Argon2; 1 is complete and tested, 2 more are mostly complete, but untestable, final 2 are completely unwritten.

  1. Blake2: a hash algorithm that produces 64-byte digests. I have this implemented and test vectors match the separate Blake2 RFC. The algorithm was extraordinary poorly documented, and took months of reverse engineering to make a Delphi port work. I created an understandable version of the Blake2 algorithm on its wikipedia page

  2. DeriveBytes: the main loop that performs the operations the specified number of times, on the parallelization number of lanes, on the specified amount of memory. This is mostly complete; but also untestable until the following two functions are written. This algorithm is horribly documented, but i believe i managed to decipher it correctly, and i created an understandable version on the Wikipedia page for Argon2

  3. Hash: a variable length hash algorithm based on Blake2, that is capable of producing digests up to the needed 1024 bytes (while Blake2 digest is fixed at 64 bytes). I have implemented this function, but it is untestable, as Argon2 has no test vectors to verify. This algorithm is horribly documented, but i believe i managed to decipher it correctly, and i created an understandable version on the Wikipedia page for Argon2

  4. GetBlockIndexes: the main DeriveBytes algorithm operates on memory in 1KB blocks arranged in a 2-d array. The i,j indexes that are operated on follow a separate algorithm. The algorithm to use depends on which variant of Argon2 you are using:

    • Argon2id
    • Argon2d
    • Argon2i

    The algorithm that explains the 3 different algorithms of selecting indexes is horribly explained in the RFC and in various whitepapers. I have no idea how it works, and the implemention remains completely empty:

    procedure TArgon2.GetBlockIndexes(i, j: Integer; out iRef, jRef: Integer); begin { We are Argon2id. } //Since i cannot make heads nor tails of either their PDF, their RFC, their GitHub, nor their sample code, this is a todo iRef := 0; jRef := 0;

    raise ENotImplemented.Create('Someone needs to figure out the 2id block schedule alorithm');

    end;

  5. G: Both the RFC and the whitepapapers (and my translation of the main algorithm on Wikipedia) refer to a function known only as G. The function is not documented anywhere. On the Wikipedia page i leave it completely unexplained:

    https://i.imgur.com/nT1mAYT.png

the same in true in the Delphi code:

//TODO: They don't document what the function G is
//B[i][j] = G(B[i][j-1], B[iref][jref])

I've committed the RFC and two variations of the whitepapers that "document" Argon2. Someone needs to decipher them, and create the GetBlockIndexes and G function.

mbtaylor1982 commented 6 years ago

Maybe i'm a fool or maybe Ii found the definition of G

2.1.4 Compression function G

Compression function G is built upon the Blake2b round function P (fully defined in Section 2.7.1). P operates on the 128-byte input, which can be viewed as 8 16-byte registers (see details below): P(A0, A1, . . . , A7) = (B0, B1, . . . , B7).

Compression function G(X, Y ) operates on two 1024-byte blocks X and Y . It first computes R = X ⊕ Y . Then R is viewed as a 8 × 8-matrix of 16-byte registers R0, R1, . . . , R63

. Then P is first applied rowwise, and then columnwise to get Z: Finally, G outputs Z ⊕ R:

Document attached below :)

Argon-v3.pdf

JeanPaulo-Eletron commented 2 years ago

now works?

DelphiWorlds commented 2 years ago

This claims to support Argon2: https://github.com/Xor-el/HashLib4Pascal Perhaps you may be able to learn from it? I'd much rather use something standalone like your library