对称加密算法性能测试并移植到Linux

evp_cipher.cpp

#include <iostream>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <fstream>
#include <ctime>

// _CRT_SECURE_NO_WARNINGS
#ifdef _WIN32
#include <openssl/applink.c>
#endif
#include "xsec.h"
using namespace std;

bool EncryptFile(string passwd, string in_filename, string out_filename,bool is_enc)
{
    //选择加解密算法,后面可以替换
    auto cipher = EVP_des_ede3_cbc();

    //输入文件大小
    int in_file_size = 0;

    //输出文件大小
    int out_file_size = 0;
    ifstream ifs(in_filename, ios::binary); //二进制打开输入文件
    if (!ifs)return false;
    ofstream ofs(out_filename, ios::binary);//二进制大小输出文件
    if (!ofs)
    {
        ifs.close();
        return false;
    }
    auto ctx = EVP_CIPHER_CTX_new(); //加解密上下文

    //密钥初始化 多出的丢弃
    unsigned char key[128] = { 0 };
    int key_size = EVP_CIPHER_key_length(cipher);// 获取密钥长度
    if (key_size > passwd.size())   //密码少了
    {
        key_size = passwd.size();
    }
    memcpy(key, passwd.data(), key_size);

    unsigned char iv[128] = { 0 }; //初始化向量
    int re = EVP_CipherInit(ctx, cipher, key, iv, is_enc);
    if (!re)
    {
        ERR_print_errors_fp(stderr);
        ifs.close();
        ofs.close();
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    unsigned char buf[1024] = { 0 };
    unsigned char out[1024] = { 0 };
    int out_len = 0;
    //1 读文件=》2 加解密文件=》3写入文件
    while (!ifs.eof())
    {
        //1 读文件
        ifs.read((char*)buf, sizeof(buf));
        int count = ifs.gcount();
        if (count <= 0)break;
        in_file_size += count; //统计读取文件大小
        //2 加解密文件 机密到out
        EVP_CipherUpdate(ctx, out, &out_len, buf, count);
        if (out_len <= 0)break;
        //3 写入文件
        ofs.write((char*)out, out_len);
        out_file_size += out_len;
    }
    //取出最后一块数据
    EVP_CipherFinal(ctx, out, &out_len);
    if (out_len > 0)
    {
        ofs.write((char*)out, out_len);
        out_file_size += out_len;
    }

    ifs.close();
    ofs.close();
    EVP_CIPHER_CTX_free(ctx);
    cout << "in_file_size:" << in_file_size << endl;
    cout << "out_file_size:" << out_file_size << endl;
    return true;
}
bool XSecEncryptFile(string passwd, string in_filename, string out_filename, bool is_enc)
{
    ifstream ifs(in_filename, ios::binary); //二进制打开输入文件
    if (!ifs)return false;
    ofstream ofs(out_filename, ios::binary);//二进制大小输出文件
    if (!ofs)
    {
        ifs.close();
        return false;
    }
    XSec sec;
    sec.Init(XAES128_CBC, "1234567812345678", is_enc);

    unsigned char buf[1024] = { 0 };
    unsigned char out[1024] = { 0 };
    int out_len = 0;
    //1 读文件=》2 加解密文件=》3写入文件
    while (!ifs.eof())
    {
        //1 读文件
        ifs.read((char*)buf, sizeof(buf));
        int count = ifs.gcount();
        if (count <= 0)break;
        bool is_end = false;
        if (ifs.eof()) //文件结尾
            is_end = true;
        out_len = sec.Encrypt(buf, count, out, is_end);
        if (out_len <= 0)
            break;
        ofs.write((char*)out, out_len);
    }
    sec.Close();
    ifs.close();
    ofs.close();
    return true;
}

//测试算法性能
class TestCipher
{
public:
    void Close()
    {
        delete in_;
        in_ = nullptr;
        delete de_;
        de_ = nullptr;
        delete en_;
        en_ = nullptr;
    }
    void Init(int data_size)
    {
        Close();
        data_size_ = data_size;
        in_ = new unsigned char[data_size];
        en_ = new unsigned char[data_size + 128];
        de_ = new unsigned char[data_size + 128];
        //测试数据赋初值
        unsigned int data = 1;
        for (int i = 0; i < data_size; i += sizeof(data))
        {
            memcpy(in_ + i, &data, sizeof(data));
            data++;
        }
        memset(en_, 0, data_size + 128);
        memset(de_, 0, data_size + 128);

    }
    void Test(XSecType type, string type_name)
    {
        memset(en_, 0, data_size_ + 128);
        memset(de_, 0, data_size_ + 128);
        cout << " ============ "<<type_name << " ============ " << endl;
        XSec sec;
        
        //加密
        sec.Init(type, passwd,true);
        auto start = clock();
        int en_size = sec.Encrypt(in_, data_size_, en_);
        auto end = clock();
        cout << "加密花费时间:" << (double)((end - start) / (double)CLOCKS_PER_SEC) << "秒" << endl;
        
        //解密
        sec.Init(type, passwd, false);
        start = clock();
        int de_size = sec.Encrypt(en_, en_size, de_);
        end = clock();
        cout  << "解密花费时间:" << (double)((end - start) / (double)CLOCKS_PER_SEC) << "秒" << endl;
    }

    ~TestCipher()
    {
        Close();
    }

private:
    //测试数字节数
    int data_size_ = 0;

    //测试数据
    unsigned char* in_ = nullptr;

    //加密后数据
    unsigned char* en_ = nullptr;

    //解密后数据
    unsigned char* de_ = nullptr;

    //密码 适应各种强度
    string passwd = "12345678ABCDEFGHabcdefgh!@#$%^&*";
};

//ci.Test(XDES_ECB, "XDES_ECB");
#define TEST_CIPHER(s) ci.Test(s, #s)
int main(int argc, char* argv[])
{
    TestCipher ci;
    ci.Init(1024 * 1024 * 100); // 100MB
    TEST_CIPHER(XDES_ECB);
    TEST_CIPHER(XDES_CBC);
    TEST_CIPHER(X3DES_ECB);
    TEST_CIPHER(X3DES_CBC);
    TEST_CIPHER(XAES128_ECB);
    TEST_CIPHER(XAES128_CBC);
    TEST_CIPHER(XAES192_ECB);
    TEST_CIPHER(XAES192_CBC);
    TEST_CIPHER(XAES256_ECB);
    TEST_CIPHER(XAES256_CBC);
    TEST_CIPHER(XSM4_ECB);
    TEST_CIPHER(XSM4_CBC);
    getchar();
    /*
    XDES_ECB,
    XDES_CBC,
    X3DES_ECB,
    X3DES_CBC,
    XAES128_ECB,
    XAES128_CBC,
    XAES192_ECB,
    XAES192_CBC, 
    XAES256_ECB,
    XAES256_CBC,
    XSM4_ECB,
    XSM4_CBC*/
    //ci.Test(XDES_ECB, "XDES_ECB");


    //加密文件
    EncryptFile("1234567812345678",
        "test_evp_cipher.cpp",
        "test_evp_cipher.encrypt2.txt",
        true);

    //解密文件
    EncryptFile("1234567812345678",
        "test_evp_cipher.encrypt2.txt",
        "test_evp_cipher.decrypt2.txt",
        false);

    //加密文件
    EncryptFile("12345678", 
        "test_evp_cipher.cpp", 
        "test_evp_cipher.encrypt.txt",
        true);
    
    //解密文件
    EncryptFile("12345678", 
        "test_evp_cipher.encrypt.txt", 
        "test_evp_cipher.decrypt.txt", 
        false);
    
    const unsigned char data[128] = "12345678123456781";//输入
    int data_size = strlen((char*)data);
    cout << "data_size = " << data_size << endl;
    unsigned char out[1024] = { 0 };                //输出
    unsigned char key[128] = "12345678901234567890";//秘钥
    unsigned char iv[128] = { 0 };                  //初始化向量
    //三重DES 3DES 算法
    auto cipher = EVP_des_ede3_cbc();
    //error:digital envelope routines:EVP_CipherInit_ex:initialization error
    //auto cipher = EVP_des_cbc();

    //获取算法的分组大小()
    int block_size = EVP_CIPHER_block_size(cipher);
    int key_size = EVP_CIPHER_key_length(cipher);
    int iv_size = EVP_CIPHER_iv_length(cipher);
    cout << "block_size = " << block_size << endl;
    cout << "key_size = " << key_size << endl;
    cout << "iv_size = " << iv_size << endl;

    //加解密上下文
    auto ctx = EVP_CIPHER_CTX_new();
    //加密算法初始化
    int re = EVP_CipherInit(ctx, cipher, key, iv,
        1  //1 表示加密
    );
    if (!re)
    {
        ERR_print_errors_fp(stderr);
        getchar();
        return -1;
    }
    cout << "EVP_CipherInit success!" << endl;

    //默认 PKCS7 补充大小 EVP_PADDING_PKCS7
    //关闭自动填充
    //EVP_CIPHER_CTX_set_padding(ctx, 0);
    EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7);
    int out_size = 0;

    //只处理分组大小得到数据,如果取消自动填充,多余数据丢弃
    // 如果自动填充,则在EVP_CipherFinal 中获取数据
    EVP_CipherUpdate(ctx,
        out,           //输出
        &out_size,     //输出数据大小
        data,          //输入数据
        data_size
    );

    cout << "EVP_CipherUpdate size:" << out_size << endl;
    //取出最后一块数据(需要填充的),或者是padding补充的数据
    int padding_size = 0;
    EVP_CipherFinal(ctx, out + out_size, &padding_size);
    cout << "padding_size = " << padding_size << endl;
    out_size += padding_size;
    cout << out_size << ":" << out << endl;

    //
    /// 解密数据 使用原来的ctx
    re = EVP_CipherInit(ctx, cipher, key, iv, 
        0 //0表示解密
    );
    if (!re)
    {
        ERR_print_errors_fp(stderr);
    }

    //解密密文后存放的明文
    unsigned char out2[1024] = { 0 };
    int out2_size = 0;
    //解密数据 填充数据取不到
    EVP_CipherUpdate(ctx,
        out2, &out2_size, //输入密文数据
        out, out_size);   //输出解密后明文
    cout << "EVP_CipherUpdate out2_size = " << out2_size << endl;

    //取出填充数据
    EVP_CipherFinal(ctx, out2 + out2_size, &padding_size);
    cout << "EVP_CipherFinal padding_size=" << padding_size << endl;
    out2_size += padding_size;
    cout << out2_size << ":" << out2 << "|" << endl;


    //释放上下文
    EVP_CIPHER_CTX_free(ctx);

    getchar();
    return 0;
}

sec.cpp

#include "xsec.h"
#include <openssl/evp.h>
#include <openssl/err.h>
#include<iostream>
using namespace std;
void XSec::Close()
{   
    //初始化iv_
    memset(iv_, 0, sizeof(iv_));
    if (ctx_)
    {
        EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)ctx_);
        ctx_ = nullptr;
    }
    
}

/
///初始化加密对象,清理之前的数据
///@para type 加密类型
///@para pass 秘钥,可以是二进制
///@is_en true加密 false解密
///@return 是否成功
bool XSec::Init(XSecType type, const std::string& pass, bool is_en)
{
    Close();
    this->type_ = type;
    this->is_en_ = is_en;
    //密钥补全或丢弃
    unsigned char key[32] = { 0 }; //少的补充0
    int key_size = pass.size();

    //加解密算法
    const EVP_CIPHER* cipher = 0;

    switch (type)
    {
    case XDES_ECB:
    case XDES_CBC:
        block_size_ = DES_KEY_SZ;
        ///密码策略,超出8字节的丢弃,少的补充0
        //超出8字节的丢弃,
        if (key_size > block_size_) key_size = block_size_;
        //少的补充0
        memcpy(key, pass.data(), key_size);
        DES_set_key((const_DES_cblock*)key, &ks_);
        return true;
    
    case X3DES_ECB:
        cipher = EVP_des_ede3_ecb();
        break;
    case X3DES_CBC:
        cipher = EVP_des_ede3_cbc();
        break;
    case XAES128_ECB:
        cipher = EVP_aes_128_ecb();
        break;
    case XAES128_CBC:
        cipher = EVP_aes_128_cbc();
        break;
    case XAES192_ECB:
        cipher = EVP_aes_192_ecb();
        break;
    case XAES192_CBC:
        cipher = EVP_aes_192_cbc();
        break;
    case XAES256_ECB:
        cipher = EVP_aes_256_ecb();
        break;
    case XAES256_CBC:
        cipher = EVP_aes_192_cbc();
        break;
    case XSM4_ECB:
        cipher = EVP_sm4_ecb();
        break;
    case XSM4_CBC:
        cipher = EVP_sm4_cbc();
        break;
    default:
        break;
    }

    if (!cipher)return false;

    //分组大小
    block_size_ = EVP_CIPHER_block_size(cipher);

    //密钥补充或者丢弃
    if (key_size > EVP_CIPHER_key_length(cipher))
        key_size = EVP_CIPHER_key_length(cipher);
    memcpy(key, pass.data(), key_size);


    //加解密上下文
    ctx_ = EVP_CIPHER_CTX_new();

    //初始化上下文
    int re = EVP_CipherInit((EVP_CIPHER_CTX*)ctx_,
        cipher,key,iv_,is_en_
        );
    if (!re) 
    {
        ERR_print_errors_fp(stderr);
        return false;
    }
    //cout << "EVP_CipherInit success!" << endl;
    return true;
}


/
/// 加解密数据
///@para in 输入数据
///@para in_size 数据大小
///@para 输出数据
///@para 成功返回加解密后数据字节大小,失败返回0
int XSec::Encrypt(const unsigned char* in, int in_size, unsigned char* out, bool is_end)
{
    if (type_ == XDES_ECB)
    {
        if (is_en_)
        {
            return EnDesECB(in,in_size,out,is_end);
        }
        else
        {
            return DeDesECB(in, in_size, out,is_end);
        }
    }
    else if (type_ == XDES_CBC)
    {
        if (is_en_)
        {
            return EnDesCBC(in, in_size, out, is_end);
        }
        else
        {
            return DeDesCBC(in, in_size, out, is_end);
        }
    }
    //不是最后一块数据,不填充PKCS7
    if (is_end)
        EVP_CIPHER_CTX_set_padding((EVP_CIPHER_CTX*)ctx_, EVP_PADDING_PKCS7);
    else
        EVP_CIPHER_CTX_set_padding((EVP_CIPHER_CTX*)ctx_, 0); //关闭自动填充
    int out_len = 0;
    EVP_CipherUpdate((EVP_CIPHER_CTX*)ctx_, out, &out_len, in, in_size);
    if (out_len <= 0)
        return 0;
    //出去填充得到数据
    int out_padding_len = 0;
    EVP_CipherFinal((EVP_CIPHER_CTX*)ctx_, out + out_len, &out_padding_len);
    return out_len+ out_padding_len;
}

/// DES ECB模式解密
int XSec::DeDesECB(const unsigned char* in, int in_size, unsigned char* out, bool is_end)
{
    for (int i = 0; i < in_size; i += block_size_)
    {
        DES_ecb_encrypt(
            (const_DES_cblock*)(in + i),
            (DES_cblock*)(out + i),
            &ks_,
            DES_DECRYPT
        );
    }
    if (is_end)
        //PKCS7 最后一个字节存储的补充字节数
        return in_size - out[in_size - 1];
    else
        return in_size;
}

/// DES ECB模式加密
int XSec::EnDesECB(const unsigned char* in, int in_size, unsigned char* out, bool is_end)
{
    ///数据填充 PKCS7 Padding
    /*
    假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;
    如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。
    */
    unsigned char pad[8] = { 0 };
    int padding_size = block_size_ - (in_size % block_size_);
    //填入补充的字节大小
    memset(pad, padding_size, sizeof(pad));
    int i = 0;
    for ( ;i < in_size; i += block_size_)
    {
        //最后一块数据,小于block_size_ 需要填充
        if (in_size - i < block_size_)
        {
            //填入数据
            memcpy(pad, in + i, in_size - i);
            break;
        }
        DES_ecb_encrypt((const_DES_cblock*)(in + i),
            (DES_cblock*)(out + i),
            &ks_,
            DES_ENCRYPT
        );
    }
    if (!is_end)return in_size;
    //补充 PKCS7结尾
    DES_ecb_encrypt((const_DES_cblock*)pad,
        (DES_cblock*)(out + i),
        &ks_,
        DES_ENCRYPT
    );
    return in_size + padding_size;
}


/// DES CBC模式加密
int XSec::EnDesCBC(const unsigned char* in, int in_size, unsigned char* out,bool is_end)
{
    //填充的数据 PKCS7 Padding
    unsigned char pad[8] = { 0 };
    int padding_size = block_size_ - (in_size % block_size_);
    //填入补充的字节大小
    memset(pad, padding_size, sizeof(pad));
    //block 整数倍大小
    int size1 = in_size - (in_size % block_size_);

    //ncbc保留iv修改 减去需要补充的数据
    DES_ncbc_encrypt(in, out,
        size1,
        &ks_,
        (DES_cblock*)iv_,
        DES_ENCRYPT
    );
    if (!is_end)return in_size;
    //PKCS7 Padding
    if (in_size % block_size_ != 0)
    {
        //复制剩余的数据
        memcpy(pad, in + size1, (in_size % block_size_));
    }
    DES_ncbc_encrypt(pad, out+size1,
        sizeof(pad),
        &ks_,
        (DES_cblock*)iv_,
        DES_ENCRYPT
    );
    return in_size + padding_size;
}


/// DES CBC模式解密
int XSec::DeDesCBC(const unsigned char* in, int in_size, unsigned char* out,bool is_end)
{
    DES_ncbc_encrypt(in, out, in_size, &ks_, (DES_cblock*)iv_, DES_DECRYPT);
    if (!is_end)return in_size;
    return in_size - out[in_size - 1];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值