First off, thanks for maintaining this package — the native FFI approach is exactly what we needed for on-device Argon2 hashing, and it's much faster than the pure-Dart alternatives.
While integrating it, we ran into a case that isn't currently handled, and I wanted to share the details (and a possible fix) in case it's helpful.
What we observed
When calling argon2() / argon2Async() with type == 2 (argon2id), the returned bytes don't match the expected hash. The call succeeds without error, but the output appears to be uninitialized memory rather than a valid hash, so verification always fails.
type == 0 (argon2d) and type == 1 (argon2i) work perfectly.
Root cause
In ios/Classes/argon2_ffi.c, hp_argon2_hash dispatches on type but only has branches for 0 and 1:
if (type == 0) {
argon2d_hash_raw(...);
} else if (type == 1) {
argon2i_hash_raw(...);
}
// type == 2 (argon2id) falls through with no branch,
// so hash1 (from malloc) is returned uninitialized.
Since there's no type == 2 branch, hash1 is never written and the function base64-encodes whatever was in the freshly-malloc'd buffer.
Suggested fix
The good news is that argon2id_hash_raw is already compiled into the bundled argon2src (declared in argon2src/argon2.h), and its signature is identical to argon2d_hash_raw. So it looks like it just needs to be wired up:
} else if (type == 2) {
argon2id_hash_raw(t_cost, m_cost, parallelism, key, keylen, salt,
saltlen,
hash1, hashlen);
}
This maps to the PHC convention also used in argon2src/argon2.h (Argon2_d = 0, Argon2_i = 1, Argon2_id = 2).
Verification
We applied this change in a local copy and tested on a real Android device (NDK 27, Flutter 3.41) against argon2id hashes generated by an independent backend (params m=102400, t=2, p=8, v=19). With the added branch, the computed hash matches the expected hash byte-for-byte, in roughly 3–500 ms.
Happy to open a PR if that's easier for you — just let me know what you'd prefer. Thanks again!
First off, thanks for maintaining this package — the native FFI approach is exactly what we needed for on-device Argon2 hashing, and it's much faster than the pure-Dart alternatives.
While integrating it, we ran into a case that isn't currently handled, and I wanted to share the details (and a possible fix) in case it's helpful.
What we observed
When calling
argon2()/argon2Async()withtype == 2(argon2id), the returned bytes don't match the expected hash. The call succeeds without error, but the output appears to be uninitialized memory rather than a valid hash, so verification always fails.type == 0(argon2d) andtype == 1(argon2i) work perfectly.Root cause
In
ios/Classes/argon2_ffi.c,hp_argon2_hashdispatches ontypebut only has branches for0and1:Since there's no
type == 2branch,hash1is never written and the function base64-encodes whatever was in the freshly-malloc'd buffer.Suggested fix
The good news is that
argon2id_hash_rawis already compiled into the bundledargon2src(declared inargon2src/argon2.h), and its signature is identical toargon2d_hash_raw. So it looks like it just needs to be wired up:This maps to the PHC convention also used in
argon2src/argon2.h(Argon2_d = 0,Argon2_i = 1,Argon2_id = 2).Verification
We applied this change in a local copy and tested on a real Android device (NDK 27, Flutter 3.41) against argon2id hashes generated by an independent backend (params
m=102400, t=2, p=8, v=19). With the added branch, the computed hash matches the expected hash byte-for-byte, in roughly 3–500 ms.Happy to open a PR if that's easier for you — just let me know what you'd prefer. Thanks again!