Reputation: 1267
In my C code, I use OpenSSL's AES in CTR mode for encryption via EVP interface, that is I have something like this:
ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv))
...
ret = EVP_EncryptUpdate(ctx, out, &outlen, in, inlen);
Length of input data isn't multiple of AES block size, so if used, say, CBC mode, I would have to allocate additional bytes for padding in output buffer.
Do I need to do the same thing in CTR mode? And also I'm curious about CFB and OFB modes.
OpenSSL man on EVP_EncryptUpdate doesn't say anything specific about "stream-like" modes, they just warn additional bytes for padding are needed.
Upvotes: 2
Views: 1849
Reputation: 38821
TLDR: EVP does not pad CTR (and other stream modes/ciphers)
Actually EVP_EncryptUpdate
itself never pads, although it can 'carry' a partial block from one call to the next; thus if the ...
in your code does not include any previous EncryptUpdate
then this (first) EncryptUpdate
will always be block-aligned and its output will never be longer:
EVP_EncryptUpdate() encrypts inl bytes from the buffer in and writes the encrypted version to out. This function can be called multiple times to encrypt successive blocks of data. The amount of data written depends on the block alignment of the encrypted data: as a result the amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1) so out should contain sufficient room. The actual number of bytes written is placed in outl. It also checks if in and out are partially overlapping, and if they are 0 is returned to indicate failure.
It is EVP_EncryptFinal[_ex]
that adds the padding and thus 'extra' output when needed as described in the next paragraph of the man page:
If padding is enabled (the default) then EVP_EncryptFinal_ex() encrypts the "final" data, that is any data that remains in a partial block. It uses standard block padding (aka PKCS padding) as described in the NOTES section, below. The encrypted final data is written to out which should have sufficient space for one cipher block. The number of bytes written is placed in outl. After this function is called the encryption operation is finished and no further calls to EVP_EncryptUpdate() should be made.
If padding is disabled then EVP_EncryptFinal_ex() will not encrypt any more data and it will return an error if any data remains in a partial block: that is if the total data length is not a multiple of the block size.
However, since the ciphertext actually consists of the output of all the Update
calls (or the call if only one) plus the output of the Final
call, the total buffer does need to be (up to) one block larger than input in cases where padding applies.
What the man page doesn't say (and should) is that padding doesn't apply to stream ciphers (like RC4) or stream modes (including CTR OFB* CFB*) at all. Each cipher/mode combination is described by an object of type EVP_CIPHER
which is a typedef for struct evp_cipher_st
; this is what EVP_aes_256_ctr()
and similar routines return a pointer to. Among other things this structure contains a field block_size
which contains, you guessed it, the block size (in bytes). For stream modes and ciphers it contains a dummy value 1 which is treated specially: EncryptFinal_ex
does not add padding even if enabled, and DecryptFinal_ex
does not remove and check padding even if enabled.
Upvotes: 2
Reputation: 102245
Do I need output buffer to be multiple of AES block size for CTR mode?
No, CTR mode does not have that requirement. In this respect, CTR mode is like OFB anb CFB mode. In contrast ECB and CBC mode requires a multiple of the block size.
OpenSSL uses the Init/Update/Final pattern, and both input and output bytes are buffered until needed. You can insert one byte at a time, if you'd like.
Internally, the EVP object will buffer input until there's enough to perform an encryption. Since CTR mode can be streamed, one output byte will be available after processing one input byte (its a simple XOR of the encrypted counter with the plain text). The EVP object will also buffer output bytes until you call Final.
Upvotes: 1