2

I want to encrypt a user's data with AES-256 to store it securely in my database. However, I have the problem that the key must be 32 characters long. But the passwords of my users are usually much shorter. Is there a way how I can "extend" the length of the passwords?

I also thought about the fact that human-made passwords are usually weak. So I would need some kind of function that "links" the password to the encryption key?

Here is my code, which I use to encrypt and decrypt:

const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key; //Here I would get the password of the user

function encrypt(text) {
   const iv = crypto.randomBytes(16);
   let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
   let encrypted = cipher.update(text);
   encrypted = Buffer.concat([encrypted, cipher.final()]);
   return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}

function decrypt(text) {
   let iv = Buffer.from(text.iv, 'hex');
   let encryptedText = Buffer.from(text.encryptedData, 'hex');
   let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
   let decrypted = decipher.update(encryptedText);
   decrypted = Buffer.concat([decrypted, decipher.final()]);
   return decrypted.toString();
}

Many thanks for answers in advance.

Update 1.0:

After some research I have found the following code: (Source)

const crypto = require('crypto');

// Uses the PBKDF2 algorithm to stretch the string 's' to an arbitrary size,
// in a way that is completely deterministic yet impossible to guess without
// knowing the original string
function stretchString(s, outputLength) {
  var salt = crypto.randomBytes(16);
  return crypto.pbkdf2Sync(s, salt, 100000, outputLength, 'sha512');
}

// Stretches the password in order to generate a key (for encrypting)
// and a large salt (for hashing)
function keyFromPassword(password) {
  // We need 32 bytes for the key
  const keyPlusHashingSalt = stretchString(password, 32 + 16);
  return {
    cipherKey: keyPlusHashingSalt.slice(0, 32),
    hashingSalt: keyPlusHashingSalt.slice(16)
  };
}

If I got everything right, this should solve my problem: From any password I can generate a secure encryption key with a given length using the above function. The same password always generates the same encryption key with the function keyFromPassword(password), right?

Update 2.0:

Thanks to @President James K. Polk, who gave me some important tips, I have now updated my code. I hope that everything is fine now.

Holla
  • 21
  • 5
  • `stretchString(password, 'salt', 24 + 48);` the salt should be unpredictable and at least 16 bytes. It can be appended/prepended to the ciphertext, it doesn't need to be a secret. `keyPlusHashingSalt.slice(0, 24)` AES-256 requires a 32 byte key; 24 bytes gives you AES-192. It's best to stick to either AES-128 or AES-256. There's nothing wrong with AES-192 but some implementations don't support it so it's the least portable. `hashingSalt: keyPlusHashingSalt.slice(24)` is this suppose to be the IV? The IV must be 16 bytes. – President James K. Polk Aug 10 '20 at 13:44

2 Answers2

1

You should not be using your user's passwords directly as keys. Instead, you can use them as input to a key-derivation algorithm like pkbdf2.

As this paper on PKBDF2 explains:

Unfortunately, user-chosen passwords are generally short and lack enough entropy [11], [21], [18]. For these reasons, they cannot be directly used as a key to implement secure cryptographic systems. A possible solution to this issue is to adopt a key derivation function (KDF), that is a function which takes a source of initial keying material and derives from it one or more pseudorandom keys.

A library for computing pkbdf2 for Node.js, for example is found here.

auspicious99
  • 3,902
  • 1
  • 44
  • 58
  • PKBDF2 and SHA is much weaker from a modern GPU/RAM brute-force attack than bcrypt https://security.stackexchange.com/questions/133239/what-is-the-specific-reason-to-prefer-bcrypt-or-pbkdf2-over-sha256-crypt-in-pass – frozen Aug 09 '20 at 15:05
  • https://stackoverflow.com/questions/44797213/bcrypt-node-js-auto-gen-a-salt-and-hash is talking about encrypting user passwords. That is a different problem from what the OP here is asking, which is to use the user passwords as the keys for encryption. – auspicious99 Aug 09 '20 at 15:06
  • @frozen https://security.stackexchange.com/questions/133239/what-is-the-specific-reason-to-prefer-bcrypt-or-pbkdf2-over-sha256-crypt-in-pass is talking about hashing passwords, which is again a different problem from what the OP is asking for help about. – auspicious99 Aug 09 '20 at 15:07
  • @auspicious99: The exact same considerations described in that link apply to the this use, so the advice given there holds true here. However, I think calling PBKDF2 "much weaker" is overstating the case. bcrypt is definitely better but PBKDF2 is ok. PBKDF2 is good enough *and* is supported by the node crypto module whereas bcrypt isn't. – President James K. Polk Aug 10 '20 at 13:50
  • @PresidentJamesK.Polk I think the security requirements for cryptographic hashes may not necessarily be the same as the security requirements for cryptographic key derivation. See https://security.stackexchange.com/questions/95410/what-is-the-difference-between-key-derivation-function-and-salted-hash#:~:text=Keys%20are%20also%20expected%20to,of%20structure%20to%20the%20output.&text=A%20secure%20password%2Dbased%20key,of%20the%20big%203%20hashes). for a discussion of the differences. – auspicious99 Aug 10 '20 at 14:08
  • (continuing) In the answer there, the last paragraph begins with "A secure password-based key derivation function is a secure password hash (PBKDF2 is in fact one of the big 3 hashes). The reverse is not necessarily true". So I don't know about the merits of using bcrypt for key derivation. – auspicious99 Aug 10 '20 at 14:08
0

Always add a salt to the text, and append it to the end of the text. The salt can be a randomly generated string of arbitrary length and can easily satisfy the 32-char length limit. In addition, adding salts before encryption strengthens the encryption.

frozen
  • 2,114
  • 14
  • 33
  • You could look at https://stackoverflow.com/questions/44797213/bcrypt-node-js-auto-gen-a-salt-and-hash which uses `bcrypt` which is a good algorithm for hashing. – frozen Aug 09 '20 at 15:00
  • I thought the OP said it is about using the user passwords as keys, not as text. That is also what their code snippet is doing. I think this answer is addressing a different problem. – auspicious99 Aug 09 '20 at 15:01