node-argon2 icon indicating copy to clipboard operation
node-argon2 copied to clipboard

Is saltLength broken? Examples attached

Open xgiovio opened this issue 1 year ago • 5 comments

async function argon2(password){
  try{
    return await a2.hash(password.normalize("NFD"), {
        type: a2.argon2id, //hybrid
        memoryCost: 2 ** 16, //64MB per thread
        hashLength: 32,
        timeCost:10,
        parallelism:4,
        saltLength:32,
        raw: false
    });
  }catch(err){
    return null;
  }
}

output has always 16 bytes random salt:

$argon2id$v=19$m=65536,t=10,p=4$oJZM5QTIRFsTy7tJgcrDHQ$JUtK3qlr7MmQZ54dSiPJhxJtux+u7W+DTZ3pvblyGzE

it however gives the correct output if i input {salt:randomValuesHere} in the object.

I would like to understand:

  1. Why the example above is not working correctly?
  2. What happens it i supply salt and saltLenght at the same? And what if saltLength is different in specified size from the salt input

Thanks

xgiovio avatar Dec 22 '24 19:12 xgiovio

Yes, saltLength has been removed as an option with the 0.40.0 release indeed, but the wiki page still had documentation on it. The reasoning is, if you're not supplying your own salt, then the default of 16 is universally regarded as safe enough for password hashing. The RFC states:

Select the salt length. A length of 128 bits is sufficient for all applications but can be reduced to 64 bits in the case of space constraints.

(see section 4. Parameter Choice)

If you need a different length, you're probably doing something other than password hashing and likely are providing your own salts.

Does this work for you? I'm not against the parameter, but I'd rather keep the library simple to avoid common mistakes - for a long time, providing your own salt was easier, and it just happened that people tended to provided their own salts, with bad quality.

What happens it i supply salt and saltLenght at the same? And what if saltLength is different in specified size from the salt input

This was never specified in documentation, but it would prefer salt over saltLength. I never expected both to be set at the same time 😆

ranisalt avatar Feb 24 '25 22:02 ranisalt

thank you for answering. yes salt is enough, i just noticed potential combinations of parameters and i made tests. But custom salt is working and enough.

The motivation in using custom salt is password derivation for password managers.

An user can choose an human password like "hello", then this password is normalized using nfd like the above example in the first post, then it is used with a random salt to derive the real password.

Now if you use this output password to encrypt and decrypt, you always need the original human password and the salt to obtain exactly the same real password.

So the custom salt is necessary for this purpose from my point of view.

xgiovio avatar Feb 24 '25 22:02 xgiovio

@xgiovio where do you need a custom salt in this scenario?

ranisalt avatar Feb 24 '25 22:02 ranisalt

well, as i said, the salt parameter is enough and changing the salt bytearray size it gives the correct raw output.

The pipeline is the following: an user choose his human password, the app creates a random salt for him using a secure random generator. The argon2 function generates the raw output. The raw output is used in the rest of the pipeline to encrypt or decrypt.

Does it make sense for you?

xgiovio avatar Feb 25 '25 00:02 xgiovio

Sort of, you're deriving a key from a password then. I'm thinking that enhancing the return value with attributes could also work, i.e. what if you run const hash = await argon2.hash(...) and they use hash.raw, hash.salt, etc to access parameters?

It's been a while that I want to have a better interface to deal with that.

ranisalt avatar Mar 14 '25 02:03 ranisalt