Agreed, utilizing GCM mode is like solving a puzzle. Some documentation would be helpful. The EVP API doesn't appear to be setup for AEAD ciphers. The attached code shows one way to use the EVP API for AES-GCM mode. Hopefully this helps.
On 03/01/2013 02:12 AM, Leon Brits wrote: > I am trying to add AES-GCM mode to my code which has been working for most > other modes for quite a while now. The mode is given as a parameter and I use > it for GCM mode to switch and do special stuff such as to set the AAD and > get/set the tag for AES-GCM mode. > > In the encipherment function I store the tag at the end of the ciphertext and > return a larger data size. In the decipherment function I automatically > reduce the size by 16 and use the last 16 bytes as the tag to compare. This > will be so documented for this mode in the library header. > > I've followed the advise of these two posting: > http://stackoverflow.com/questions/12153009/openssl-c-example-of-aes-gcm-using-evp-interfaces > and > http://incog-izick.blogspot.in/2011/08/using-openssl-aes-gcm.html > > My problem is that the call to get the tag fails (EVP_CIPHER_CTX_ctrl() > returns 1) in the encipherment function. > > Can anybody shine some light on what my problem may be? (I can post code if > you want, but the referenced links contain good code already) > > I am working on Ubuntu 12.10 which has the following OpenSSL installed: > > $ openssl version -a > > OpenSSL 1.0.1 14 Mar 2012 built on: Tue Aug 21 05:18:48 UTC 2012 platform: > debian-amd64 options: bn(64,64) rc4(16x,int) des(idx,cisc,16,int) > blowfish(idx) compiler: cc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS > -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 > -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security > -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-Bsymbolic-functions > -Wl,-z,relro -Wa,--noexecstack -Wall -DOPENSSL_NO_TLS1_2_CLIENT > -DOPENSSL_MAX_TLS1_2_CIPHER_LENGTH=50 -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 > -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM > -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM > -DWHIRLPOOL_ASM -DGHASH_ASM OPENSSLDIR: "/usr/lib/ssl" > > ______________________________________________________________________ > OpenSSL Project http://www.openssl.org > Development Mailing List openssl-dev@openssl.org > Automated List Manager majord...@openssl.org > . >
/* Example compiler command: gcc -g gcmtest.c -L/nobackup/tmp/x1/openssl-1.0.1c -lcrypto */ #include <stdio.h> #include <string.h> #include <openssl/evp.h> #define PTLEN 60 #define TAGLEN 8 #define IVLEN 12 #define AADLEN 20 #define KEYLEN 16 static unsigned char Payload[PTLEN] = { 0xd9,0x31,0x32,0x25,0xf8,0x84,0x06,0xe5, 0xa5,0x59,0x09,0xc5,0xaf,0xf5,0x26,0x9a, 0x86,0xa7,0xa9,0x53,0x15,0x34,0xf7,0xda, 0x2e,0x4c,0x30,0x3d,0x8a,0x31,0x8a,0x72, 0x1c,0x3c,0x0c,0x95,0x95,0x68,0x09,0x53, 0x2f,0xcf,0x0e,0x24,0x49,0xa6,0xb5,0x25, 0xb1,0x6a,0xed,0xf5,0xaa,0x0d,0xe6,0x57, 0xba,0x63,0x7b,0x39 }; static unsigned char AAD[AADLEN] = { 0xfe,0xed,0xfa,0xce,0xde,0xad,0xbe,0xef, 0xfe,0xed,0xfa,0xce,0xde,0xad,0xbe,0xef, 0xab,0xad,0xda,0xd2 }; static unsigned char IV[IVLEN] = { 0xca,0xfe,0xba,0xbe,0xfa,0xce,0xdb,0xad,0xde,0xca,0xf8,0x88 }; static unsigned char Key[KEYLEN] = { 0xfe,0xff,0xe9,0x92,0x86,0x65,0x73,0x1c, 0x6d,0x6a,0x8f,0x94,0x67,0x30,0x83,0x08 }; #if 0 static unsigned char ctexpect[68] = { 0x42,0x83,0x1e,0xc2,0x21,0x77,0x74,0x24, 0x4b,0x72,0x21,0xb7,0x84,0xd0,0xd4,0x9c, 0xe3,0xaa,0x21,0x2f,0x2c,0x02,0xa4,0xe0, 0x35,0xc1,0x7e,0x23,0x29,0xac,0xa1,0x2e, 0x21,0xd5,0x14,0xb2,0x54,0x66,0x93,0x1c, 0x7d,0x8f,0x6a,0x5a,0xac,0x84,0xaa,0x05, 0x1b,0xa3,0x0b,0x39,0x6a,0x0a,0xac,0x97, 0x3d,0x58,0xe0,0x91, /* the last 8 bytes are the tag */ 0x5b,0xc9,0x4f,0xbc,0x32,0x21,0xa5,0xdb, }; #endif static unsigned char CT[512]; static void dump_hex(char *lbl, unsigned char *c, int len) { int i; printf("\n%s: ", lbl); for (i=0; i<len; i++) { printf("%02x ", c[i]); } printf("\n"); } /* * This is an example program that encrypts and then decrypts * using AES-128 GCM mode. The OpenSSL 1.0.1c GCM interface is * primarily setup for TLS, which uses a 12 byte IV and 16 byte * tag and 13 bytes of AAD. Using alternate values for these * parameters is more challenging. Hence, this code shows one * way to use the EVP interface for AES GCM mode when not doing * TLS. Note: there are probably other ways to skin this cat. */ int main (int argc, char *argv[]) { EVP_CIPHER_CTX ctx; const EVP_CIPHER *gcm = EVP_aes_128_gcm(); unsigned char *tag; unsigned char ptbuf[512]; unsigned char tagbuf[16]; unsigned char *ctbuf; int rv; EVP_CIPHER_CTX_init(&ctx); /* * Init the cipher and set the key */ EVP_CipherInit_ex(&ctx, gcm, NULL, Key, NULL, 1); /* * Set the IV * Note: Be sure to use a value of 0 when invoking with EVP_CTRL_GCM_IV_GEN, * otherwise the data pointed to by the IV paramter will be modified by * libcrypto. */ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, IVLEN, 0); EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IV_FIXED, -1, IV); if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_IV_GEN, 0, IV)) { printf("\nFailed to set IV");; exit(2); } /* * Process the AAD */ rv = EVP_Cipher(&ctx, NULL, AAD, AADLEN); if (rv != AADLEN) { printf("\nSet AAD rv=%d\n", rv); exit(2); } /* * Process the plaintext */ EVP_Cipher(&ctx, CT, Payload, PTLEN); dump_hex("CT", CT, PTLEN); /* * This is goofy, but we need to invoke EVP_Cipher again to calculate the tag */ EVP_Cipher(&ctx, NULL, NULL, 0); /* * OK, now that the tag has been calculated, get the TAG and display it. * A real application would typically include the tag along with the * ciphertext when transmitting to a peer. */ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, TAGLEN, tagbuf); dump_hex("TAG", tagbuf, TAGLEN); /* * Note, if you fail to cleanup, there will be a memory leak. */ EVP_CIPHER_CTX_cleanup(&ctx); /************************************************************************************ ************************************************************************************ ************************************************************************************ * OK, now let's decrypt and see if the original plaintext matches ************************************************************************************ ************************************************************************************ ************************************************************************************/ tag = tagbuf; ctbuf = CT; /* * Note that this pretty much just does a memory clear of the structure. * Because were doing another init on the same context. EVP_CIPHER_CTX_cleanup() * must be called above. Otherwise we would have a memory leak. */ EVP_CIPHER_CTX_init(&ctx); /* * Init the cipher and set the key */ EVP_CipherInit_ex(&ctx, gcm, NULL, Key, NULL, 0); /* * Set the IV */ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, IVLEN, 0); EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IV_FIXED, -1, IV); if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_IV_GEN, 0, IV)) { printf("\nFailed to set IV");; exit(2); } /* * Set dummy tag before processing AAD. Otherwise the AAD can * not be processed. */ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, TAGLEN, ptbuf); /* * Process the AAD */ rv = EVP_Cipher(&ctx, NULL, AAD, AADLEN); if (rv != AADLEN) { printf("\nSet AAD rv=%d\n", rv); exit(2); } /* * Set the tag when decrypting */ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, TAGLEN, tag); /* * Decrypt the ciphertext */ EVP_Cipher(&ctx, ptbuf, ctbuf, PTLEN); /* * Check the tag */ rv = EVP_Cipher(&ctx, NULL, NULL, 0); if (rv) { printf("\nGCM decrypt failed due to tag mismatch (%d)\n", rv); exit(2); } /* * The tag was good, it's save to use the plaintext. */ dump_hex("PT2", ptbuf, PTLEN); /* * Cleanup again to avoid memory leak */ EVP_CIPHER_CTX_cleanup(&ctx); /* * Compare to original plaintext to see if the test passed */ if (!memcmp(ptbuf, Payload, PTLEN)) { printf("\nGCM works!!!\n"); } else { printf("\nGCM failed!!! Original plaintext mismatch\n"); } }
<<attachment: foleyj.vcf>>