Search code examples
encryptionhexaesencryption-symmetric

How to generate a AES-256 CBC key/iv that can be shared as a string?


I am trying to make AES-256 CBC encryption work in PHP, Ruby (using SymmetricEncryption) and Javascript (using CryptoJS). As for the first 2:

<?php
openssl_encrypt(
  'Hello!', 'aes-256-cbc',
  '1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF',
  0,
  '1234567890ABCDEF1234567890ABCDEF'
); // => 'BAd5fmmMTvRE4Ohvf3GpCw=='
ruby_cipher = SymmetricEncryption::Cipher.new(
  key: "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF",
  iv: "1234567890ABCDEF1234567890ABCDEF",
  cipher_name: 'aes-256-cbc'
)
ruby_cipher.encrypt("Hello!") # => 'BAd5fmmMTvRE4Ohvf3GpCw=='

But according to this answer the above key/iv only provide 128 bit security.

PHP and Ruby take the key and IV as a binary string. They don't assume that it is Hex-encoded. So, although this key has 256 bits in it, the security is actually only 128 bits, because each character has only 4 bit in a Hex-encoded string.

So using only half of the key/iv provides the same encryption result in CryptoJS.

CryptoJS.AES.encrypt(
    "Hello!",
    CryptoJS.enc.Utf8.parse('1234567890ABCDEF1234567890ABCDEF'),
    iv: CryptoJS.enc.Utf8.parse('1234567890ABCDEF')
).toString() // 'BAd5fmmMTvRE4Ohvf3GpCw=='

How do I generate string key and iv's that provide 256 bit security?


Solution

  • You use a key generator, and if not available, a random number generator to generate a key of the correct size, in this case 32 bytes. You can feed that to the cipher implementation. Then, if you need hexadecimals then you can convert or encode them explicitly to hexadecimals after.

    Of course, to decrypt (or encrypt again) you'd first have to decode or parse the hexadecimal string back to the actual binary key.

    Basically you'd use the hexadecimals to represent the bytes or octets, but you never use the hexadecimals directly.


    Note that usually hexadecimal strings are not used. I'd only use them to test code. In general keys are put in (PKCS#12) key stores, or they are generated by a key derivation method. Hexadecimals are generally only needed for human consumption and this is generally not required. One reason not to encode to hexadecimals is that strings are sometimes hard to remove from memory, so it may well be that the hexadecimal key remains in memory after use.