openssl aes api 记录 [一]

2 篇文章 0 订阅

EVP实现AES加解密

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/evp.h>
#include <openssl/aes.h>

int main(void)
{
    unsigned char userkey[EVP_MAX_KEY_LENGTH];
    unsigned char iv[EVP_MAX_IV_LENGTH];
    //    unsigned char *date = (unsigned char *)malloc(AES_BLOCK_SIZE*3);
    int dateLen = 35;													//******* [1] *******
    unsigned char *date = (unsigned char *)malloc(dateLen);
    unsigned char *encrypt = (unsigned char *)malloc(AES_BLOCK_SIZE*6);
    unsigned char *plain = (unsigned char *)malloc(AES_BLOCK_SIZE*6);
    EVP_CIPHER_CTX ctx;													//******* [6] *******
    int ret;
    int tlen = 0;
    int mlen = 0;
    int flen = 0;

    memset((void*)userkey, 'k', EVP_MAX_KEY_LENGTH);
    memset((void*)iv, 'i', EVP_MAX_IV_LENGTH);
    memset((void*)date, 'p', dateLen);
    memset((void*)encrypt, 'H', AES_BLOCK_SIZE*6);
    memset((void*)plain, 0, AES_BLOCK_SIZE*6);

    /*初始化ctx*/
    EVP_CIPHER_CTX_init(&ctx);											//******* [7] *******

    /*指定加密算法及key和iv(此处IV没有用)*/
    ret = EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, userkey, iv);
    if(ret != 1) {
        printf("EVP_EncryptInit_ex failed\n");
        exit(-1);
    }

    /*禁用padding功能*/
    EVP_CIPHER_CTX_set_padding(&ctx, 0);								//******* [2] *******
    
    /*进行加密操作*/
    ret = EVP_EncryptUpdate(&ctx, encrypt, &mlen, date, dateLen);		//******* [3] *******
    if(ret != 1) {
        printf("EVP_EncryptUpdate failed\n");
        exit(-1);
    }
    /*结束加密操作*/
    ret = EVP_EncryptFinal_ex(&ctx, encrypt+mlen, &flen);				//******* [4] *******
    if(ret != 1) {
        printf("EVP_EncryptFinal_ex failed\n");
        exit(-1);
    }

    tlen = mlen + flen;													//******* [5] *******	

    tlen = 0;
    mlen = 0;
    flen = 0;

    EVP_CIPHER_CTX_cleanup(&ctx);
    EVP_CIPHER_CTX_init(&ctx);											//******* [8] *******

    ret = EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, userkey, iv);
    if(ret != 1) {
        printf("EVP_DecryptInit_ex failed\n");
        exit(-1);
    }

    EVP_CIPHER_CTX_set_padding(&ctx, 0);
    ret = EVP_DecryptUpdate(&ctx, plain, &mlen, encrypt, AES_BLOCK_SIZE*3);
    if(ret != 1) {
        printf("EVP_DecryptUpdate failed\n");
        exit(-1);
    }

    ret = EVP_DecryptFinal_ex(&ctx, plain+mlen, &flen);
    if(ret != 1) {
        printf("EVP_DecryptFinal_ex failed\n");
        exit(-1);
    }
    /*对比解密后与原数据是否一致*/
    if(!memcmp(plain, date, dateLen)) {
        printf("test success\n");
    } else {
        printf("test failed\n");
    }

    printf("encrypt: ");
    int i;
    for(i = 0; i < AES_BLOCK_SIZE*3+4; i ++){
        printf("%.2x ", encrypt[i]);
        if((i+1)%32 == 0){
            printf("\n");
        }
    }
    printf("\n");
    for(i = 0; i < dateLen; i ++){
        printf("%.2x ", date[i]);
        if((i+1)%32 == 0){
            printf("\n");
        }
    }
    printf("\n");
    for(i = 0; i < AES_BLOCK_SIZE*3; i ++){
        printf("%.2x ", plain[i]);
        if((i+1)%32 == 0){
            printf("\n");
        }
    }
    printf("\n");
#endif

    return 0;
}

本文中有一个很不明白的点,共有三个len变量,分别是tlen,mlen,flen,分别是什么作用
基于这个问题,在[1]处,重新指定了源数据长度为35,

  1. debug发现:
  • 当[2]处设置禁用padding时:
    在[3]处,mlen值为32;
    在[4]处,flen值为0,并且EVP_EncryptFinal_ex返回0,即失败。
  • 当[2]处注释,则:
    [3] mlen值为32;
    [4] flen值为16;
    [5] tlen值为48。
  1. 综上所述,结合Openssl Manpage

If padding is enabled (the default) then EVP_EncryptFinal_ex() encrypts the “final” data, that is any data that remains in a partial block. It uses standard block padding (aka PKCS padding) as described in the NOTES section, below. The encrypted final data is written to out which should have sufficient space for one cipher block. The number of bytes written is placed in outl. After this function is called the encryption operation is finished and no further calls to EVP_EncryptUpdate() should be made.
If padding is disabled then EVP_EncryptFinal_ex() will not encrypt any more data and it will return an error if any data remains in a partial block: that is if the total data length is not a multiple of the block size.

可得:若禁用padding,则需要确认加密源数据为16字节的整数倍,否则最后生于不足16字节的数据将不加密;如果使用padding,则末尾不足16字节,openssl将做补齐。

2019/4/11 更:

问题一

  • 现象: [6] 处提示"不完整的类型",
  • 解决方法:here

问题二

  • 现象:将项目移植到Windows下时,编译通过,运行莫名其妙中断,debug发现在 [6] 处发生内存访问异常。
  • 解决方法:查阅资料得知 EVP_CIPHER_CTX_init() 接口用于对ctx清零,注释掉 [7],执行memset(&ctx, 0, sizeof(EVP_CIPHER_CTX));,o**k,成功。
    不过有一点很奇怪,在 [8] 处同样调用了 EVP_CIPHER_CTX_init() 接口,但是没报错,还没找到原因。

DemoCode2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值