简体   繁体   中英

Does Node's crypto decipher always throw an error if the password is wrong?

I'm creating a little game-like feature for fun (so no need to be super secure).

On the server, I encrypt using a secret password:

const key = crypto.createCipher('aes-256-cbc', 'secret')
let encryption = key.update('cheerio', 'utf8', 'hex')
encryption += key.final('hex')

On the client, I want the user to guess the password (which is secret in this example), like this:

try {
    const key = crypto.createDecipher('aes-256-cbc', guess)
    let decryption = key.update(encryption, 'hex', 'utf8')
    decryption += key.final('utf8')
 }
catch(err) {
    console.log("err", err)
 }

The question is, will this always throw an error if the guess fails, or do I need to compare it to my phrase ( 'cheerio' )? (I am yet to guess something that doesn't throw an error.)

I feel the former would give an extra layer of security, because then there's both a secret password AND secret word, while if I do a compare on the client the secret word is exposed in the code.

No, an error is not always generated when guess fails.

The reason for the error ( error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt ), is a wrong padding during decryption, here . The crypto module uses PKCS7 padding by default. In this padding variant each padding byte has the value that corresponds to the number of padding bytes, eg 01 , 0202 , 030303 , 04040404 etc., see here for details. Decryption with an incorrect password will result in random/corrupted plaintext. Its end will generally not correspond to a valid PKCS7 padding, which causes the error. However, by chance a plaintext may result, whose end matches a valid PKCS7 padding. In this case, no error is raised. Eg a 01 byte terminating the plaintext would be compatible with PKCS7 padding, which occurs for a random password with a probability of 1/256. The same applies to 0202 with a probability of 1/65536, and so on.

This can be easily verified if padding is disabled during decryption ( key.setAutoPadding(false) ). Then no error is raised. The same applies when using a stream cipher mode (eg, CTR) where padding is implicitly disabled.

This means that even in cases where no error is produced, a comparison with the plain text is necessary.

Note that createCipher (deprecated, by the way) derives a key and an IV from the password. The same password (and thus the same key and IV) will generate the same ciphertext for the same plaintext. Therefore, a comparison of the ciphertexts serves the same purpose as a comparison of the plaintexts.

One more thing, the results of update and final must be concatenated, otherwise the result is generally not complete, ie in encryption = key.final('hex') the = must be replaced by += , although this is probably just a typo. The same applies to decryption.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM