首页 > 编程语言 >使用OpenSSl库实现AES-GCM-128算法(C语言)

使用OpenSSl库实现AES-GCM-128算法(C语言)

时间:2024-10-23 15:01:32浏览次数:1  
标签:AES ctx GCM ciphertext len OpenSSl char EVP unsigned

在C语言中使用OpenSSL库实现AES-GCM-128算法,并生成GMAC(Galois Message Authentication Code)消息认证码,通过以下步骤完成:

  1. 初始化加密环境:创建一个EVP_CIPHER_CTX结构体,用于存储加密过程中的所有必要信息。
  2. 设置加密算法:指定使用AES-GCM模式,以及密钥和IV(初始化向量)。
  3. 处理附加认证数据(AAD):如果有不需要加密但需要进行认证的数据,可以在加密之前设置。
  4. 加密数据:将明文数据进行加密,得到密文。
  5. 生成GMAC:在加密完成后,通过EVP_CIPHER_CTX_ctrl函数获取GMAC。
  6. 初始化解密环境:与加密类似,创建并初始化EVP_CIPHER_CTX结构体。
  7. 设置解密算法:指定使用AES-GCM模式,以及密钥和IV。
  8. 处理附加认证数据(AAD):与加密时相同,设置相同的AAD数据。
  9. 解密数据:将密文数据进行解密,得到明文。
  10. 验证GMAC:在解密完成后,通过EVP_CIPHER_CTX_ctrl函数设置预期的GMAC,并调用EVP_DecryptFinal_ex函数来验证GMAC是否正确。

具体实现如下:
加密函数

点击查看代码 int aes_gcm_encrypt(const unsigned char* plaintext, int plaintext_len, const unsigned char* key, const unsigned char* iv, const unsigned char* aad, int aad_len, unsigned char* ciphertext, unsigned char* gmac, int gmac_len) { EVP_CIPHER_CTX* ctx; int len; int ciphertext_len;
//创建初始化加密上下文
if (!(ctx = EVP_CIPHER_CTX_new())) 
{
    fprintf(stderr, "Error creating cipher context.\n");
    return 0;
}

//使用aes_128_gcm算法初始化加密操作
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv)) 
{
    fprintf(stderr, "Error initialising encryption.\n");
    return 0;
}

//设置附加认证数据(AAD)
if (aad_len > 0) 
{
    if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) 
    {
        fprintf(stderr, "Error setting AAD.\n");
        return 0;
    }
}

//加密数据
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) 
{
    fprintf(stderr, "Error encrypting plaintext.\n");
    return 0;
}
ciphertext_len = len;

//结束加密操作
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) 
{
    fprintf(stderr, "Error finalising encryption.\n");
    return 0;
}
ciphertext_len += len;

//获取GMAC消息认证码
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, gmac_len, gmac)) 
{
    fprintf(stderr, "Error getting GMAC.\n");
    return 0;
}

//释放ctx结构体
EVP_CIPHER_CTX_free(ctx);

//返回加密后的长度
return ciphertext_len;

}

解密函数:

点击查看代码 int aes_gcm_decrypt(const unsigned char* ciphertext, int ciphertext_len, const unsigned char* key, const unsigned char* iv, const unsigned char* aad, int aad_len, unsigned char* plaintext, const unsigned char* gmac, int gmac_len) { EVP_CIPHER_CTX* ctx; int len; int plaintext_len; int ret;
//创建初始化解密上下文
if (!(ctx = EVP_CIPHER_CTX_new())) 
{
    fprintf(stderr, "Error creating cipher context.\n");
    return 0;
}

//使用aes_128_gcm算法初始化解密操作
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv)) 
{
    fprintf(stderr, "Error initialising decryption.\n");
    return 0;
}

//设置附加认证数据(AAD)
if (aad_len > 0) {
    if (1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) 
    {
        fprintf(stderr, "Error setting AAD.\n");
        return 0;
    }
}

//解密数据
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) 
{
    fprintf(stderr, "Error decrypting ciphertext.\n");
    return 0;
}
plaintext_len = len;

//设置GMAC消息认证码
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, gmac_len, (void*)gmac)) 
{
    fprintf(stderr, "Error setting tag.\n");
    return 0;
}

//结束解密操作,验证附加数据的完整性
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
if (ret > 0) 
{
    plaintext_len += len;
}
else 
{
    fprintf(stderr, "Error finalising decryption.\n");
    return 0;
}

//释放ctx结构体
EVP_CIPHER_CTX_free(ctx);

//返回明文长度
return plaintext_len;

}

主函数:

点击查看代码 int main() { unsigned char key[AES_KEY_SIZE]; unsigned char iv[GCM_IV_SIZE]; unsigned char aad[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; unsigned char plaintext[] = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}; unsigned char* ciphertext; unsigned char gmac[GCM_TAG_SIZE]; int ciphertext_len;
//初始化密钥和 IV
memset(key, 0x00, sizeof(key));
memset(iv, 0x00, sizeof(iv));
//RAND_bytes(key, sizeof(key));
//RAND_bytes(iv, sizeof(iv));

//为密文存储开辟空间
ciphertext = OPENSSL_malloc(sizeof(plaintext) + EVP_MAX_BLOCK_LENGTH);
if (!ciphertext) 
{
    fprintf(stderr, "Could not allocate memory for ciphertext.\n");
    return 1;
}

ciphertext_len = aes_gcm_encrypt(plaintext, sizeof(plaintext), key, iv, aad, sizeof(aad), ciphertext, gmac, GCM_TAG_SIZE);
if (ciphertext_len > 0) 
{
    printf("Ciphertext is:\n");
    xprint(ciphertext, ciphertext_len);
    printf("GMAC is:\n");
    xprint(gmac, sizeof(gmac));

    unsigned char decryptedtext[128];
    int decryptedtext_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, iv, aad, sizeof(aad), decryptedtext, gmac, GCM_TAG_SIZE);
    if (decryptedtext_len > 0) 
    {
        printf("Decrypted text is:\n");
        xprint(decryptedtext, decryptedtext_len);
    }
    else 
    {
        fprintf(stderr, "Error decrypting plaintext.\n");
    }
}
else 
{
    fprintf(stderr, "Error encrypting plaintext.\n");
}

//释放空间
OPENSSL_free(ciphertext);
return 0;

}

运行结果:

标签:AES,ctx,GCM,ciphertext,len,OpenSSl,char,EVP,unsigned
From: https://www.cnblogs.com/twd-log/p/18496382

相关文章

  • Windows下给Visual Studio添加OpenSSL
    一、安装OpenSSL1.下载OpenSSLWin32/Win64OpenSSLInstallerforWindows-ShiningLightProductions可以下载已经编译好的包含lib和include文件的安装包有Win32和Win64可选,这里的位数指的是你使用OpenSSL开发出来的软件的位数版本,而不是你计算机的位数。注意,不要下载......
  • Linux(银河麒麟)升级openssh和openssl
    Linux升级openssh升级包下载地址:openssh:https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.8p1.tar.gzopenssl:https://github.com/openssl/openssl/releases/download/openssl-3.3.2/openssl-3.3.2.tar.gzzlib:https://zlib.net/fossils/zlib-1.3.tar.gz备份原......
  • AES初探
    AES为分组密码,每次加密一组数据使用不同长度的密钥,加密的轮数也不同加密公式C=E(K,P)下面介绍加密轮函数的四个操作:字节代换、行位移、列混合、轮密钥加以AES-128为例字节代换字节代换通过S盒进行一个查表映射的方式,将明文字节映射成S盒中的字节映射逻辑是这样的:分别取......
  • 使用AES 128位加解密,加解密模式采用CBC,填充模式采用PKCS5Padding的Java工具方法示例
    importjavax.crypto.Cipher;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;importjava.util.Base64;publicclassAESUtils{privatestaticfinalStringAES_ALGORITHM="AES/CBC/PKCS5Padding";private......
  • GCM
    GaloisCounterMode(GCM)运算符与函数$0^s$包含了$s$个$0$的比特串。$\mbox{CIPH}_K⁡(X)$在密钥$K$下对分组$X$应用分组密码得到的输出。$\mbox{GCTR}_K⁡(ICB,X)$在密钥K下对包含初始组计数$ICB$的比特串X应用包含给定分组加密的$\mbox{GCTR}$函数的输出。$\m......
  • Kylinv10 curl报错:SSLv3_client_method version OPENSSL_1_1_0 not define
    curl http://127.0.0.1出现问题#curlhttps://www.example.comcurl:relocationerror:/lib64/libcurl.so.4:symbolSSLv3_client_methodversionOPENSSL_1_1_0notdefinedinfilelibssl.so.1.1withlinktimereference错误是/usr/lib64中的动态链接中无法识别......
  • openssl 1.1.1 安装
    https://download.csdn.net/blog/column/10942194/125836859root@VM-0-10-ubuntu:/home/ubuntu#wgethttps://www.openssl.org/source/openssl-1.1.1n.tar.gzopenssl:errorwhileloadingsharedlibraries:libssl.so.1.1在执行opensslversion出现如下错误:openssl:erro......
  • openssl实验截图记录
                                    ......
  • AES加密,全平台实现!
    前言今天我们来聊聊数据加密与隐私相关话题。本人开发的加密工具,欢迎体验!https://www.pgyer.com/cryptotools。AES加密,通俗的话来讲,就是用一个key把原数据变成一个新数据,也通过这个key还原成原数据。所以,它是一种对称的加密方式。只要别人不知道这个key,就无法解开数据的内......
  • crit: Microsoft.AspNetCore.Server.Kestrel[0] Unable to start Kestrel. Interop+Cr
    域名证书没有放在指定的位置错误信息crit:Microsoft.AspNetCore.Server.Kestrel[0]UnabletostartKestrel.Interop+Crypto+OpenSslCryptographicException:error:2006D080:BIOroutines:BIO_new_file:nosuchfileatInterop.Crypto.CheckValidOpenSslHandle(Saf......