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

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

时间:2024-10-24 15:51:14浏览次数:3  
标签: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://blog.csdn.net/2201_75357739/article/details/143184907

相关文章

  • 【高届数,往届EI检索】第十届能源资源与环境工程研究进展国际学术会议(ICAESEE 2024)
    第十届能源资源与环境工程研究进展国际学术会议(ICAESEE2024)定于2024年12月20-22日在湖南长沙举办。会议主要围绕能源资源与环境工程等研究领域展开讨论。会议旨在为从事能源材料与电力电气研究的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术,了解学术......
  • OpenSSL异步模式流程梳理
    源码来源于OpenSSLMasterCommitIDd550d2aae531c6fa2e10b1a30d2acdf373663889。总览核心入口函数为ssl_start_async_job,以SSL_do_handshake为入口举例分析,同时通过标注步骤【1~N】,来明确阅读的顺序。步骤【1】到步骤【18】为一个阶段步骤【19】到步骤【23】为一个阶......
  • 使用OpenSSl库实现AES-GCM-128算法(C语言)
    在C语言中使用OpenSSL库实现AES-GCM-128算法,并生成GMAC(GaloisMessageAuthenticationCode)消息认证码,通过以下步骤完成:初始化加密环境:创建一个EVP_CIPHER_CTX结构体,用于存储加密过程中的所有必要信息。设置加密算法:指定使用AES-GCM模式,以及密钥和IV(初始化向量)。处理附加认证......
  • 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......