0
$\begingroup$

I am using CryptoJS AES 256 encryption:

CryptoJS.AES.encrypt(realData, generateKey(passphrase), {iv: iv});

The secret is generated through:

function generateKey(passphrase) {
  const salt = CryptoJS.lib.WordArray.random(128 / 8);
  const key256Bits = CryptoJS.PBKDF2(passphrase, salt, {
    keySize: 256 / 32,
    iterations: randomNumber,
  });

  return key256Bits;
}

Im new to this and wondering how secure is the 256keybits above?

Can someone use brute force to find out the hex, base64 encoding strings of the 256keybits, iv without caring about the passphrase.

Then convert the real 256keybits, iv which used to decrypt the realData in AES encryption? Or can the 256keybits be brute force?

Thanks!

$\endgroup$
1
$\begingroup$

The value for iterations: randomNumber is not supposed to be a random number. It's an iteration count that controls the cost of PBKDF2. It's supposed to be set as high as tolerable in the application, and the protection afforded by PBKDF2 against password search grows about linearly with that parameter. In the following I assume a high iterations (say a baseline of a hundred thousand), and that salt gets stored someway. I also assume it's used HMAC-SHA-1 (the default) or HMAC-SHA-256 (also common).

As far a we know, the main weakness in what's described is that it's possible to test a passphrase, by running generateKey, and then testing the corresponding key using a known AES cryptogram. Is that "without caring about the passphrase"? That's unclear to me.

Problem is, PBKDF2 can be run at very high speed by attackers using GPUs, FPGAs or ASICs. When iterations is high (as it should), PBKDF2 is the bottleneck of generateKey and password search. So adversaries can search passwords orders of magnitude faster than normal users using CryptoJS. From the standpoint of making password search hard, which is it's main goal in the question, PBKDF2 is thus among the worst possible use of spare CPU power for key stretching when it comes to powerful adversaries. Much better options ar Argon2, scrypt, or even bcrypt.

You decide if it's coincidental that the NIST formerly recommended PBKDF2, and still does not mandate using something better; like it formerly pushed Dual_EC_DRBG, with the obvious intention of allowing US intelligence to break this crypto. Hanlon's razor may apply, but I hold NIST scientists in higher esteem.

$\endgroup$
5
  • $\begingroup$ "without caring about the passphrase"? I mean the passphase passed into generateKey(passphrase) could contain special characters to make it strong for brute force. While the key returned from generateKey(passphrase) which I can use to encrypt and decrypt the realData in CryptoJS.AES.encrypt(realData, generateKey(passphrase), {iv: iv}) is array of bytes. Since bytes is new to me so I don't know if that is hard to brute foce and put back to decryption as key. $\endgroup$ – Kim Mỹ Jun 24 at 7:05
  • $\begingroup$ Also the encoding readable(Hex, Base64) string of generateKey(passphrase) (which in Crypto-JS I can just use key256Bits.toString(<-- base64 or hex -->)) does not contain any special characters if hex or only '/,+' and wierd ending '==' if base64. And that is easy for brute force then convert back to array of bytes(the returned key from generateKey(passphrase)) then put into decrypt the realData? Sorry this is new to me and correct me if i'm wrong. Thanks! $\endgroup$ – Kim Mỹ Jun 24 at 7:05
  • $\begingroup$ in Crypto-JS library, provided the encoding readable(Hex, Base64) string of generateKey(passphrase), I can just use CryptoJS.enc.Hex.parse() to get the real 256keybits and decrypt the realData without even care about the passphrase passed into generateKey(passphrase) to generate the decrypting key? $\endgroup$ – Kim Mỹ Jun 24 at 7:13
  • 1
    $\begingroup$ It's no easier to brute force a 256-bit key expressed as a 43-character Base64 string than it is to brute-force the 32-byte raw equivalent. And that's essentially impossible. Correctly encoding the output of PBKDF2 to make an AES key with all 256-bit is an important detail. I assumed its none right. That's a programming issue, highly dependent on CryptoJS, thus rather off-topic. I did not discuss it. $\endgroup$ – fgrieu Jun 24 at 8:23
  • 1
    $\begingroup$ (@KimMỹ+) crypto-js.PBKDF2 returns a WordArray which is a javascript 'object' type that contains bytes (but is not e.g. javascript's builtin Unit8Array); if you convert this to a string (e.g. by console.log) that result is encoded in base64 but if you pass it as the key to a crypto-js.Cipher instance that uses the bytes in it, whereas if you pass a (builtin) string to such an instance it applies an OpenSSL-defined and quite poor PBKDF (EVP_BytesToKey with niter=1) and also by default uses the OpenSSL-defined format with Salted__+8bytes prepended to the ciphertext and encoded in base64. $\endgroup$ – dave_thompson_085 Jun 24 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.