I want to use TweetNaCl.js for encrypting user data that is stored in LocalStorage
. Therefore, I want to prompt the user to provide a PIN/password that shall be used to derive a key that is then used as a secret key for TweetNaCl's secretbox.
Looking for a modern scrypt implementation in JavaScript, I couldn't find any implementation that is actively maintained / worked on in the past 4 years and that doesn't ship their own SHA-256, PBKDF2, HMAC implementation, but would use standard Web Crypto API [1].
I've came up with this implementation so far, which is based upon the original codebase of scrypt-js:
https://github.com/jsheaven/scrypt/blob/main/src/scrypt.ts but I switched out a few crucial parts of the implementation with their Web Crypto API counterparts and I'm wondering if what I have come up so far is safe and secure. All the original Unit Tests are working fine so far, and I've also added my own test suite on top of it.
However, I'm not an expert in crypto so please advice me if there is anything I could have missed.
I'm especially scratching my head about this part:
export const PBKDF2_HMAC_SHA256_OneIteration = async (
crypto: Crypto,
password: Array<number>,
salt: Array<number>,
derivedKeyLength: number,
): Promise<Array<number>> => {
const originalKey = await crypto.subtle.importKey('raw', new Uint8Array(password), 'PBKDF2', false, ['deriveBits'])
const derivedKey = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt: new Uint8Array(salt),
iterations: 1,
hash: 'SHA-256',
},
originalKey,
derivedKeyLength * 8, // The key length must be specified in bits
)
return Array.from(new Uint8Array(derivedKey))
}
I'm aware that Array<number>
and copying buffers around isn't a great idea, also from a performance perspective. I'm just following the original scrypt-js
internal data structures atm and still thinking to refactor everything to use Uint8Array
- but that's something for future optimizations.
My main question is: Is this a correct implementation to derive a key following PBKDF2-HMAC-SHA-256
using the Web Crypto API from a security perspective?
Everything is green in my unit tests, so this suggests that it's functional, but there seem to be endless possibilities to go wrong when sailing the seas of crypto, so please enlighten me :)
Thanks alot and best!
[1] https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits