I have written a cryptography NPM package called kruptein. The code is also hosted on GitHub.
Having used multiple "best practices" with regards to key management, algorithm selection, key size, iv size etc. I could use someone with experience in this area to help validate the implementation.
I could use some help determining if I have flaws in any of the following:
Key sizes:
_matrix(algo)
- Are the appropriate key, iv & authentication tag sizes being identified and used correctly based on the algorithm selection? i.e. AES-128-CBC or AES-256-XTS_matrix(algo) { let obj = { at_size: 16, iv_size: 16, key_size: 32 }; if (algo.match(/ccm|ocb|gcm/i)) obj.iv_size = 12; if (algo.match(/aes/) && algo.match(/ecb/)) obj.iv_size = 0; if (algo.match(/aes/) && algo.match(/128/)) obj.key_size = 16; if (algo.match(/aes/) && algo.match(/192/)) obj.key_size = 24; if (algo.match(/aes/) && algo.match(/xts/)) obj.key_size = 32; if (algo.match(/aes/) && algo.match(/xts/) && algo.match(/256/)) obj.key_size = 64; return obj; } }
Key derivation:
_derive_key(secret)
- When deriving keyed material from a provided secret are enough iterations used? Is there a problem with the salt generation used for the resulting keyed material? What about the resulting key? For both the IV and key I am concerned about possible weakening of the material when converting to a buffer and slicing to the appropriate sizes._derive_key(secret) { let key, hash, salt, result, derived_key; try { hash = this.crypto.createHash(this.hashing); hash.update(secret); salt = hash.digest(); } catch(err) { throw err; } salt = (Buffer.isBuffer(salt)) ? salt.slice(0, 16) : salt.substr(0, 16); key = this.crypto.pbkdf2Sync(secret, salt, 10000, 64, this.hashing); return Buffer.from(key.toString(this.encodeas)).slice(0, this.key_size); }
IV generation:
_iv(iv_size)
- When generating a new IV is there a problem with slicing the results. Most of the node.js crypto API functions use buffers and the sizes must match but I can't help but think it is weakening the IV._iv(iv_size) { let iv = this.crypto.randomBytes(iv_size); return Buffer.from(iv.toString(this.encodeas), this.encodeas).slice(0, iv_size); }
master
, which is not a defined deeplink, and therefore may point to a revision different from the one you're presenting here. To avoid confusion a community member linked to a specfic revision. And secondly they also edited the title to be more in line with the title format this community expects. As such the edit was IMO a definitive improvement and should remain applied. \$\endgroup\$