下例是基于 openssl-3.0.13 编码
gcc -o aes_gcm aes_gcm.c -I/xxx/openssl/openssl-3.0.13/include -L/xxx/openssl/openssl-3.0.13/lib64 -lssl -lcrypto
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#define AES_KEY_SIZE 256
#define GCM_IV_SIZE 12
#define GCM_TAG_SIZE 16
void handleErrors(void)
{
fprintf(stderr, "An error occurred\n");
exit(1);
}
int encrypt_data(const unsigned char *plaintext, int plaintext_len
, unsigned char *key, unsigned char *iv, int iv_len
, unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
if (!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
handleErrors();
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, GCM_TAG_SIZE, tag))
handleErrors();
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt_data(const unsigned char *ciphertext, int ciphertext_len
, unsigned char *key, unsigned char *iv, int iv_len
, unsigned char *decryptedtext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
if (!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, GCM_IV_SIZE, NULL))
handleErrors();
if (1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
handleErrors();
#if 0
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, GCM_TAG_SIZE, tag))
handleErrors();
#endif
if (1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, GCM_TAG_SIZE, tag))
handleErrors();
if (1 != EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len))
handleErrors();
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
int main()
{
unsigned char *plaintext = "Hello, AES-GCM";
unsigned char key[AES_KEY_SIZE/8];
unsigned char iv[GCM_IV_SIZE];
unsigned char ciphertext[128];
int ciphertext_len;
unsigned char tag[GCM_TAG_SIZE];
unsigned char decryptedtext[128];
int decryptedtext_len;
int i;
RAND_bytes(key, sizeof(key));
RAND_bytes(iv, sizeof(iv));
ciphertext_len = encrypt_data(plaintext, strlen((char *)plaintext)
, key, iv, GCM_IV_SIZE, ciphertext, tag);
printf("Plaintext: %s\n", plaintext);
printf("Ciphertext: ");
for (i = 0; i < ciphertext_len; i++)
printf("%02X", ciphertext[i]);
printf("\n");
decryptedtext_len = decrypt_data(ciphertext, ciphertext_len
, key, iv, GCM_IV_SIZE, decryptedtext, tag);
decryptedtext[decryptedtext_len] = '\0';
printf("Decrypted text: %s\n", decryptedtext);
return 0;
}
对于大多数需要认证加密的应用程序,GCM 应该被认为优于 CCM