AES-128-CCM - "iv must be 7 bytes"
harry-m opened this issue · comments
Issue: when trying to decrypt AES-128-CCM, I pass a 16 byte IV but receive an error saying that a 7byte IV is required:
code.rb:27:in `iv=': iv must be 7 bytes (ArgumentError)
The code:
def decrypt(ct_blob, secret)
key = OpenSSL::PKCS5.pbkdf2_hmac(Base64.decode64(secret), Base64.decode64(ct_blob[:salt]), 1000, 16, 'SHA256')
c = OpenSSL::Cipher::AES128.new(:CCM)
c.decrypt
c.key = key
c.iv = Base64.decode64(ct_blob[:iv])
c.update(Base64.decode64(ct_blob[:ct]))
end
I'm very confused by this because my understanding was that AES uses a 16 byte block and that the IV is the same as the block size. The size of Base64.decode64(ct_blob[:iv])
is a 16 bytes as expected.
Am I missing something obvious? I have traced it back to a check in ossl_cipher.c:515
:
if (RSTRING_LEN(iv) != iv_len)
ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
But haven't got very far poking around in openssl - I wanted to check because it seems much more likely that I'm doing something wrong than that there's a bug in openssl.
Grateful for any steer.
CCM mode is based on CTR mode. The nonce (which OpenSSL conveniently calls "IV") will be shorter than the block length. According to RFC 3610, a valid nonce length for AES-CCM is 7..13 octets and OpenSSL happens to choose 7 octets as the default.
Due to the streaming-style API of OpenSSL::Cipher (EVP_CIPHER_CTX), the CCM support unfortunately is convoluted. You will have to use OpenSSL::Cipher#auth_tag_len=
, #iv_len=
, and #ccm_data_len=
in the correct order (this is different from other AEAD modes such as GCM, which don't require these).
You might find this test case in Ruby/OpenSSL useful:
openssl/test/openssl/test_cipher.rb
Lines 168 to 208 in 79aa330