下面分三部分给出:
GCM (Galois/Counter Mode)是一种同时提供加密(Confidentiality)和认证(Authenticity)的分组密码工作模式。它用 CTR 模式做流加密,用 GHASH 做消息认证。
下面给出一个简单的 reference model,使用 OpenSSL EVP API 实现 AES-GCM 和 SM4-GCM 的加解密。编译成动态库后,可由 SystemVerilog DPI-C 调用。
/* ref_gcm.c */
#include
#include
#include
#include
/*
* Encrypt (or decrypt) in GCM mode
* - cipher: EVP_aes_128_gcm(), EVP_aes_256_gcm(), EVP_sm4_gcm() (OpenSSL1.1.1+)
* - is_enc: 1=encrypt, 0=decrypt
* - tag_len: 推荐16
* 返回 0=OK, <0=ERR
*/
static int gcm_crypt(const EVP_CIPHER *cipher,
const uint8_t *key, int key_len,
const uint8_t *iv, int iv_len,
const uint8_t *aad, int aad_len,
const uint8_t *in, int in_len,
uint8_t *out,
uint8_t *tag, int tag_len,
int is_enc)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len, ret = -1;
if(!ctx) return -1;
if(1 != EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, is_enc)) goto end;
// IV 长度
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL);
// Key & IV
if(1 != EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, is_enc)) goto end;
// AAD
if(aad && aad_len>0){
if(1 != EVP_CipherUpdate(ctx, NULL, &len, aad, aad_len)) goto end;
}
// 数据
if(in && in_len>0){
if(1 != EVP_CipherUpdate(ctx, out, &len, in, in_len)) goto end;
}
// Encrypt Final / Get plaintext
if(1 != EVP_CipherFinal_ex(ctx, out+len, &len)) goto end;
// Tag
if(is_enc){
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag)) goto end;
} else {
// 验证 tag
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) goto end;
}
ret = 0;
end:
EVP_CIPHER_CTX_free(ctx);
return ret;
}
// AES-128-GCM
int aes128_gcm_encrypt(const uint8_t *key, const uint8_t *iv, int iv_len,
const uint8_t *aad, int aad_len,
const uint8_t *pt, int pt_len,
uint8_t *ct, uint8_t *tag)
{
return gcm_crypt(EVP_aes_128_gcm(), key, 16, iv, iv_len, aad, aad_len, pt, pt_len, ct, tag, 16, 1);
}
int aes128_gcm_decrypt(const uint8_t *key, const uint8_t *iv, int iv_len,
const uint8_t *aad, int aad_len,
const uint8_t *ct, int ct_len,
const uint8_t *tag,
uint8_t *pt)
{
return gcm_crypt(EVP_aes_128_gcm(), key, 16, iv, iv_len, aad, aad_len, ct, ct_len, pt, (uint8_t*)tag, 16, 0);
}
// SM4-GCM (OpenSSL 1.1.1+ 支持)
int sm4_gcm_encrypt(const uint8_t *key, const uint8_t *iv, int iv_len,
const uint8_t *aad, int aad_len,
const uint8_t *pt, int pt_len,
uint8_t *ct, uint8_t *tag)
{
return gcm_crypt(EVP_sm4_gcm(), key, 16, iv, iv_len, aad, aad_len,