Reputation: 353
I am fixing this issue. Reading the issue will give you a better picture of the problem, nonetheless I'm writing the issue here in my own language here.
This is how system should work:
User inputs
text
and apassword
, it gets saved in a file after strong encryption. When user inputsencryptedText
andpassword
, it returns the decrypted text. Currently the encryption is handled usingCrypto
library of node.js, function usedcreateCipher
.
Problem: The solution works very well with createCipher
but it does not employ any kind of salt mechanism. Openssl recommends to use use pbkdf2 for deriving keys. I understand why it is necessary, because otherwise encrypted value of a text will be same always(e.g. encryption of "1234" with the same password will always result in "xyz"), which makes rainbow table attack easy/possible.
Solution I'm trying: I started implementing Openssl's suggestion to have key derivation mechanism using pbkdf2, but I'm not quite able to grasp how should it be done properly. Please help me understand and figure out the right approach for this issue. I am thinking of following approach but a lot of things seem to be missing
deriveKey(password)
: create hash for the password string using a random salt and any hashing algo("sha256" probably), iterations = 64000.
derivedKey = crypto.pbkdf2Sync(password, salt=crypto.randomBytes(256), iterations, 512, 'sha256',...)
encrypt(text, derivedKey, cb)
:
cipherObject
using derivedKey
:cipherObject = createCipheriv(algo="aes-256-cbc", derivedKey, iv2=randomBytes(256),...)
cipherText = cipherObject.update(text,...)
encryptedText
:1:salt;iters:IV:cipherText
in a file locally (thanks to @bartonjs for making me understand this)decrypt(encryptedText, password)
:
So the text to decrypt looks like this: 1:salt;iters:IV:cipherText
derivedKey = pbkdf2Sync(password, salt, iters, 'sha256')
decipherObject = createDecipherIv("aes-256-cbc", derivedKey, IV...)
text = decipherObject.update(cipherText,...)
My 3 big questions in order of priority
P.S. I'm not an expert of cryptography, would be helpful to get opinion from one
Upvotes: 0
Views: 936
Reputation: 81
I'm assuming you don't want to implement it yourself if you don't have to. And as CodeCaster said, if you don't have solid knowledge of it, you really shouldn't be the one implementing it.
My suggestion is to use the Stanford Javascript Encryption Library (sjcl) which has support for pbkdf2.
Check out their demo page, which allows you to encrypt a message with a password and a random salt:
https://bitwiseshiftleft.github.io/sjcl/demo/
And here's a link to the demo source, which should give you an idea of how to implement it with their library: https://github.com/bitwiseshiftleft/sjcl/blob/master/demo/example.js
Edit (bumping from the comments to an answer) As josh3736 pointed out in the comments, no third-party library is necessary. Node's crypto module natively supports pbkdf2. He provided the following link as an example: https://cafedev.org/article/2016/06/secure-text-encryption-with-nodejs/
Upvotes: 0
Reputation: 33286
For decryption I think I will have to save salt of derivedKey as well with iv. I don't know if that would compromise the security or not. What should be the solution?
A salt
, from the NIST glossary:
A non-secret value that is used in a cryptographic process, usually to ensure that the results of computations for one instance cannot be reused by an Attacker.
SOURCE: SP 800-63; CNSSI-4009
Since it's defined as a "non-secret" value, writing it next to the IV does not compromise security.
Note that you also should write the iteration count for PBKDF2.
salt;iters:IV:cipherText
("Startup", "IV", "ciphertext" separated by colons, and startup is broken into "salt" and "iteration count" by a semi-colon, so parsing isn't ambiguous as the structure evolves... for best results, something in the beginning would be a "schema value", like the number 1, for v1 of your file format, like 1:salt;iters:IV:cipherText
).
Upvotes: 1