Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

Configuring CryptoJS to Use SHA256 HMAC with PBKDF2 for Added Security

The security of sensitive information is of utmost importance today. One way to enhance the security of stored passwords is by using PBKDF2 with SHA256 HMAC, a cryptographic algorithm that adds an extra layer of protection if the password hashes are compromised. I covered recently how to calculate PBKDF2 yourself with Python, but today needed to do the same with Javascript.

Having just tried out CryptoJS to do some AES decryption, I thought I'll try the library's PBKDF2() function as well.

CryptoJS documentation on PBKDF2 is as scarce as everything on this library, and trying out the 256 bit key example with Node.js gives the following output:

$ node
Welcome to Node.js v19.6.0.
Type ".help" for more information.
> const crypto = require('crypto-js')
undefined
> const key = crypto.PBKDF2("password", "salt", {keySize: 256/32, iterations: 4096})
undefined
> crypto.enc.Hex.stringify(key)
'4b007901b765489abead49d926f721d065a429c12e463f6c4cd79401085b03db'

Now let's recall what Python gave here:

$ python
Python 3.10.7 (tags/v3.10.7:6cc6b13, Sep  5 2022, 14:08:36) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import hashlib
>>> hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 4096).hex()
'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a'
>>>

Uh-oh, they don't match! Now looking at pbkdf2.js in the CryptoJS Github source, we can see that the algorithm defaults to SHA-1:

 cfg: Base.extend({
            keySize: 128/32,
            hasher: SHA1,
            iterations: 1
        }),

Seeing how keySize and iterations are overridden, we only need to locate the SHA256 in proper namespace to guide the implementation to use SHA256 HMAC instead:

$ node
Welcome to Node.js v19.6.0.
Type ".help" for more information.
> const crypto = require('crypto-js')
undefined
> const key = crypto.PBKDF2("password", "salt", {keySize: 256/32,
...     iterations: 4096, hasher: crypto.algo.SHA256})
undefined
> crypto.enc.Hex.stringify(key)
'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a'

Awesome! Now we are ready to rock'n'roll with a proper hash function.