基于openssl的EVP对称加密C语言单独实现

基于openssl的EVP对称加密C语言单独实现


《基于openssl的EVP对称加密C语言实战案例》这篇博客的基础上将代码提出到独立的.c文件,可以单独进行编译和运行。

代码实现

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <errno.h>

#define CIPHER_TEXT_LEN 128
#define ETH_ALEN        6
#define ESP_OK          0
#define ESP_ERR         -1

const char gszKey[] = "111112222333344445555666677";
/***************************************************************************
function: ESP_GetKey
input:
output:
Description:获取解密需要的key,key的长度是32实际使用27个
            代码混淆生成key防止直接硬编码被看出来
****************************************************************************/
void ESP_GetKey(char *pcKey)
{
    pcKey[0]='3';
    pcKey[1]=pcKey[0]-1;
    pcKey[2]='a';
    pcKey[3]=pcKey[2]+1;
    pcKey[4]=pcKey[3]+1;
    pcKey[5]='G';
    pcKey[6]=pcKey[4]+1;
    pcKey[7]=pcKey[1]+1;
    pcKey[8]=pcKey[0]+1;
    pcKey[9]=pcKey[1];
    pcKey[10]=pcKey[6]-1;
    pcKey[11]=pcKey[7]+1;
    pcKey[12]=pcKey[5]+1;
    pcKey[13]=pcKey[5]-1;
    pcKey[14]=pcKey[4]-1;
    pcKey[15]=pcKey[0];
    pcKey[16]=pcKey[6]-1;
    pcKey[17]=pcKey[5]-1;
    pcKey[18]=pcKey[17]+1;
    pcKey[19]=pcKey[18]-1;
    pcKey[20]=pcKey[5]-1;
    pcKey[21]=pcKey[3];
    pcKey[22]=pcKey[1]+1;
    pcKey[23]=pcKey[22]+1;
    pcKey[24]=pcKey[18]-1;
    pcKey[25]=pcKey[5]+1;
    pcKey[26]=pcKey[16];
    pcKey[27]=pcKey[0]+1;
    pcKey[28]=pcKey[12]+1;
    pcKey[29]=pcKey[5]+1;
    pcKey[30]=pcKey[11]-1;
    pcKey[31]=pcKey[6]-1;

    return;
}

int ESP_Encrypt(unsigned char *ucPlaintext, int ucPlaintextLen, unsigned char *ucCiphertext)
{
    int   ret              = ESP_ERR;
    int   p_len            = 0;
    int   f_len            = 0;
    int   ciphertextLen    = 0;
    int   nrounds          = 5;
    char  szKey[32]        = {0};
    unsigned char key[32]  = {0};
    unsigned char iv[32]   = {0};
    unsigned int  szSalt[] = {11111,11111};

    printf("ucPlaintext:%s, ucPlaintextLen:%d.\n", ucPlaintext, ucPlaintextLen);
    EVP_CIPHER_CTX *pMdCtx;

    pMdCtx = EVP_CIPHER_CTX_new();
    if(NULL == pMdCtx)
    {
        printf("alloc ctx failed.\n");
        return ESP_ERR;
    }

    ESP_GetKey(szKey);
    ret = EVP_BytesToKey(EVP_aes_256_cbc(), 
                          EVP_sha1(), 
                          (unsigned char*)szSalt, 
                          (unsigned char*)szKey, 
                          strlen(gszKey),
                          nrounds, 
                          key, 
                          iv);
    if(ret != 32)
    {
        printf("Key size is %d bits, it should be 256 bits\n", ret);
        EVP_CIPHER_CTX_free(pMdCtx);
        return ESP_ERR;
    }

    EVP_EncryptInit_ex(pMdCtx, EVP_aes_256_cbc(), NULL, key, iv);

    EVP_EncryptUpdate(pMdCtx, ucCiphertext, &p_len, ucPlaintext, ucPlaintextLen);
    ciphertextLen = p_len;
    EVP_EncryptFinal_ex(pMdCtx, ucCiphertext + p_len, &f_len);
    ciphertextLen += f_len;
    ucCiphertext[p_len+f_len] = 0;

    printf("p_len is %d, f_len is %d, ucCiphertext is %s.\n", p_len, f_len, ucCiphertext);
    EVP_CIPHER_CTX_free(pMdCtx);

    //写入文件中
    FILE *fp = fopen("/home/lyp/key", "w");
    if(fp == NULL)
    {
        printf("generate key file failed!\n");
        return ESP_ERR;
    }

    //fprintf(fp, "%s", ucCiphertext);
    fwrite(ucCiphertext, p_len+f_len, 1, fp);
    fclose(fp);

    return ciphertextLen;
}

unsigned char *ESP_DecryptKey(unsigned char *pcCipherText, int lCipherLen)
{
    int   ret;
    int   nrounds   = 5;
    char  szKey[32] = {0};
    int   p_len     = 0;
    int   f_len     = 0;
    unsigned int  szSalt[] = {11111,11111};
    unsigned char key[32]  = {0};
    unsigned char iv[32]   = {0};
    EVP_CIPHER_CTX *pMdCtx = NULL;
    unsigned char *pcPlaintext = NULL;

    // 0 准备明文空间和上下文
    pcPlaintext = (unsigned char *)malloc(lCipherLen);
    if(NULL == pcPlaintext)
    {
      printf("System have no more memory failed.\n");
      return NULL;
    }

    pMdCtx = EVP_CIPHER_CTX_new();
    if(NULL == pMdCtx)
    {
        free(pcPlaintext);
        printf("alloc ctx failed.\n");
        return NULL;
    }

    // 1 获取key和iv 然后初始化ctx
    ESP_GetKey(szKey);
    ret = EVP_BytesToKey(EVP_aes_256_cbc(), 
                          EVP_sha1(), 
                          (unsigned char*)szSalt, 
                          (unsigned char*)szKey, 
                          strlen(gszKey),
                          nrounds, 
                          key, 
                          iv);

    if(ret != 32)
    {
        printf("Key size is %d bits, it should be 256 bits\n", ret);
        EVP_CIPHER_CTX_free(pMdCtx);
        free(pcPlaintext);
        return NULL;
    }
    EVP_DecryptInit_ex(pMdCtx, EVP_aes_256_cbc(), NULL, key, iv);

    // 2解密
    EVP_DecryptUpdate(pMdCtx, pcPlaintext, &p_len, pcCipherText, lCipherLen);
    EVP_DecryptFinal_ex(pMdCtx, pcPlaintext+p_len, &f_len);
    pcPlaintext[p_len+f_len]=0;

    printf("p_len is %d, f_len is %d, pcPlaintext is %s.\n", p_len, f_len, pcPlaintext);

    // 3释放上下文
    EVP_CIPHER_CTX_free(pMdCtx);

    return pcPlaintext;
}

int main(int argc, char *szMacAddr[])
{
    unsigned char szCipherTxt[CIPHER_TEXT_LEN] = {0};
    char          szBuffer[CIPHER_TEXT_LEN]    = {0};
    char          szBufferTmp[CIPHER_TEXT_LEN] = {0};
    char          *pcKey = NULL;

    sprintf(szBuffer, "%sFC-TOP-ROOF", szMacAddr[1]);
    printf("szBuffer:%s, sizeof(szBuffer):%ld.\n", szBuffer, sizeof(szBuffer));
    strncpy(szBufferTmp, szBuffer, sizeof(szBufferTmp));
    //加密,生成key文件,并返回出参加密字符串szCipherTxt
    ESP_Encrypt(szBuffer, sizeof(szBuffer), szCipherTxt);
    //解密,并返回解密字符串
    pcKey = (char *)ESP_DecryptKey(szCipherTxt, sizeof(szCipherTxt));

    if(NULL == pcKey)
    {
        printf("Decrypt failed.\n");
        return ESP_ERR;
    }

    //校验结果,比较解密字符串与加密前字符串是否一样
    if(strcmp(szBufferTmp, pcKey))
    {
        printf("check key is invaild, buffer:%s, key:%s.\n", szBufferTmp ,pcKey);
        free(pcKey);
        return ESP_ERR;
    }
    else
    {
        printf("check key success.\n");
    }
    free(pcKey);
    return ESP_OK;
}

运行结果

lyp@ubuntu:~$ gcc key.c -lcrypto
lyp@ubuntu:~$ ./a.out 11-22-33-44-55-66
szBuffer:11-22-33-44-55-66FC-TOP-ROOF, sizeof(szBuffer):128.
ucPlaintext:11-22-33-44-55-66FC-TOP-ROOF, ucPlaintextLen:128.
p_len is 128, f_len is 16, ucCiphertext is @q⚌1| Z ⚌ ⚌ ⚌ P ⚌ ⚌ 氤 l ] ⚌ ⚌ ⚌ Z⚌⚌⚌P⚌⚌氤l]⚌⚌⚌ ZPl]⚌⚌1H⚌⚌⚌z⚌⚌⚌dDJ⚌⚌~r⚌⚌⚌"ф⚌⚌⚌p⚌ߡ?⚌˿⚌w2⚌%⚌’⚌s⚌⚌⚌⚌⚌U⚌⚌⚌V奫L7⚌⚌?v⚌⚌⚌⚌,⚌O⚌
⚌⚌`⚌⚌⚌)⚌uL⚌⚌v⚌զ⚌2⚌iT⚌⚌⚌⚌⚌⚌6A⚌z⚌].
p_len is 112, f_len is 0, pcPlaintext is 11-22-33-44-55-66FC-TOP-ROOF.
check key success.
lyp@ubuntu:~$
在这里插入图片描述

说明

1.编译时需要链接动态库 libcrypt.so,这个库是软链接的libcrypto.so.1.1。
库文件获取:
openssl编译需要链接的库libcrypto.so
在这里插入图片描述
2.运行 a.out时可以带一个字符串参数,上述运行结果模拟的是mac地址。

3.代码中的 szSaltnroundsgszKeyszKey变量可自行修改,保证自己代码的保密性和独立性(要注意加密接口与解密接口中相同变量的一致)。

4.头文件可能引用大于实际需要。

5.CIPHER_TEXT_LEN 长度设置成32时,解密key文件得到的字符串不完整,具体情况如下:
lyp@ubuntu:~$ ./a.out 11-22-33-44-55-66
szBuffer:11-22-33-44-55-66FC-TOP-ROOF, sizeof(szBuffer):32.
ucPlaintext:11-22-33-44-55-66FC-TOP-ROOF, ucPlaintextLen:32.
p_len is 32, f_len is 16, ucCiphertext is @q⚌1| Z ⚌ ⚌ ⚌ P ⚌ ⚌ 氤 l ] ⚌ ⚌ ⚌ Z⚌⚌⚌P⚌⚌氤l]⚌⚌⚌ ZPl]⚌⚌"⚌⚌⚌⚌⚌1⚌u/D⚌p⚌⚌.
p_len is 16, f_len is 0, pcPlaintext is 11-22-33-44-55-6.
check key is invaild, buffer:11-22-33-44-55-66FC-TOP-ROOF, key:11-22-33-44-55-6.
在这里插入图片描述
但是在上一篇文章中就没有出现该问题;当CIPHER_TEXT_LEN设置成128时,生成的key又不可以应用于上一篇文章中的项目,希望有心人可以帮忙解惑。
答:加密接口调用ESP_Encrypt(szBuffer, sizeof(szBuffer), szCipherTxt);参数传的有问题,将sizeof(szBuffer)改成strlen(szBuffer),问题解决。
6.代码生成的key文件在下面链接可以获取。
openssl加密生成的key文件

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值