On 5 March 2013 14:13, Dr. Stephen Henson <[email protected]> wrote:
> On Tue, Mar 05, 2013, Leon Brits wrote:
>
> > Just want to add that I do set the data sizes before EncryptUpdate and
> > DecryptUpdate and mentioned in the CCM section of the OpenSSL support
> page.
> > This page does answer both my questions (appologies), but I still fail to
> > decrypt.
> >
>
> I'll add an example for CCM mode in the demos section shortly. CCM mode is
> a
> bit picky about setting all the parameters correctly in the correct order.
>
That would be good!! I am working on some test code myself but cannot get
it to work. See source code below. This is adapted from some code I have
for GCM that works fine. With CCM though encryption (apparently) works
fine, but when I get to decryption I get a 0 response from the final
EVP_DecryptUpdate call - no error message on the OpenSSL error stack :-(
Happy for you to use this for your demo code - if you can tell me how to
fix it!! :-)
Any clues?
Thanks
Matt
int encryptccm(unsigned char *plaintext, int plaintext_len, unsigned char
*aad,
int aad_len, unsigned char *key, unsigned char *iv,
unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. */
if(!EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
handleErrors();
/* Setting IV len to 7. Not strictly necessary as this is the default
* but shown here for the purposes of this example */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
handleErrors();
/* Initialise key and IV */
if(!EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Provide the total plaintext length
*/
if(!EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_len))
handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Get the tag */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decryptccm(unsigned char *ciphertext, int ciphertext_len, unsigned char
*aad,
int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
handleErrors();
/* Setting IV len to 7. Not strictly necessary as this is the default
* but shown here for the purposes of this example */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL))
handleErrors();
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, tag))
handleErrors();
/* Provide the total ciphertext length
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, NULL, ciphertext_len))
handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!(ret = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext,
ciphertext_len)))
handleErrors();
plaintext_len = len;
/* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0)
{
/* Success */
plaintext_len += len;
return plaintext_len;
}
else
{
/* Verify failed */
return -1;
}
}