编程技术记录

世界你好!

AES加密几个要点

  • 对称加密(Symmetry Crypto)
    加密和解密的钥匙是同一把—-加密方和解密方拥有相同的密钥(音yue,四声)。

  • 密钥(key)
    任意数据(不一定非得字符串),长度常见为128比特、192比特、256比特,也有支持512比特的算法库

  • 初始化向量(IV)
    这不是AES算法标准强制要求的,是一种增加AES破解难度的手段。IV和密钥共同参与加密和解密运算。IV长度固定为128比特。

  • 加密块(block)
    每次加密的块长度都是128比特;输入和输出长度相同,考虑补全模式的情况下,输出的最大长度 = 输入长度+128比特

  • 加密模式
    是指当需要加密的源数据长度大于128比特时,加密块和加密块之间的运算模式。
    常见的有 CBC密码分组链接模式、ECB电码本模式(不推荐)、CTR计算器模式、CFB密码反馈模式、OFB输出反馈模式。

  • 补全模式模式(padding)
    因为AES一个加密块为16字节,当源数据的最后一个块不足16字节时,需要手动补全为16字节。

一般使用PKCS7模式,手动补全N个N,N为不足的字节数。

例如,最后一个块为 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10
需要补6个字节,那么就是6个6
 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 0x06 0x06 0x06 0x06 0x06 0x06

EVP AES 加密


#include "openssl/crypto.h"
#include "openssl/aes.h"
#include "openssl/evp.h"

//引入c++的string,作为buffer使用
#include <string>

//std::string 作为返回值其实可以右值优化的。
std::string encrypt(std::string &data , std::string &key ,std::string &iv)
{
     //这里应该做必要的参数校验,如检查key和iv长度
    //指定算法模式
    EVP_CIPHER *ciper = NULL;
    switch (data.size())
    {
        case 128 / 8: ciper =  EVP_aes_128_cbc();break;
        case 192 / 8: ciper =  EVP_aes_192_cbc();break;
        case 256 / 8: ciper =  EVP_aes_256_cbc();break;
        default:return "需要做一些错误处理";
    }

    //初始化ctx
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);

    //指定加密算法及key和iv
    int ret = EVP_EncryptInit_ex(ctx, ciper, NULL, (unsigned char *)key.c_str(),  (unsigned char *)iv.c_str());
    if(ret != 1)
    {//EVP_EncryptInit_ex failed
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }

    // 设置padding EVP框架默认使用的就是PKCS7
    EVP_CIPHER_CTX_set_padding(ctx, 1);

   std::string buffer;
   buffer.append(0,AES_BLOCK_SIZE + data.size());

    int mlen = 0;
    //进行加密操作
    ret = EVP_EncryptUpdate(ctx, (unsigned char *)buffer.c_str(), &mlen, (unsigned char *)data.c_str(),(int)buffer.size());
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }

    int flen = 0;
    //结束加密操作
    ret = EVP_EncryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &flen);
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return "需要做一些错误处理";
    }
    EVP_CIPHER_CTX_free(ctx);
    buffer.resize(mlen + flen);
    return buffer;
}

EVP AES 解密


std::string decrypt(std::string &data , std::string &key ,std::string &iv)
{
   //这里应该做必要的参数校验,如检查key和iv长度
    //指定算法模式
    EVP_CIPHER *ciper = NULL;
    switch (data.size())
    {
        case 128 / 8: ciper =  EVP_aes_128_cbc();break;
        case 192 / 8: ciper =  EVP_aes_192_cbc();break;
        case 256 / 8: ciper =  EVP_aes_256_cbc();break;
        default:return "需要做一些错误处理";
    }

    //初始化ctx
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);

    //指定加密算法及key和iv
    int ret = EVP_DecryptInit_ex(ctx, ciper, NULL,  (unsigned char *)key.c_str(),  (unsigned char *)iv.c_str());
    if(ret != 1)
    {//EVP_EncryptInit_ex failed
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    // 设置padding功能 EVP框架默认使用的就是PKCS7
    EVP_CIPHER_CTX_set_padding(ctx, 1);

    std::string buffer;
    buffer.append(0,data.size());

    int mlen = 0;
    //进行解密操作
    ret = EVP_DecryptUpdate(ctx,  (unsigned char *)buffer.c_str(), &mlen,  (unsigned char *)data.c_str(),(int) data.size());
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    int flen = 0;
    //结束解密操作
    ret = EVP_DecryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &flen);
    if(ret != 1)
    {
        EVP_CIPHER_CTX_free(ctx);
        return  "需要做一些错误处理";
    }

    EVP_CIPHER_CTX_free(ctx);
    buffer.resize(mlen + flen);
    return buffer;
}

发表回复

© Beli. All Rights Reserved.