调用openssl实现加解密算法

        由于工作中涉及到加解密,包括Hash(SHA256)算法、HMAC_SHA256 算法、ECDH算法、ECC签名算法、AES/CBC 128算法一共涉及5类算法,笔者通过查询发现openssl库以上算法都支持,索性借助openssl库实现上述5类算法。笔者用的openssl库版本为 OpenSSL 1.1.1k 。

Hash(SHA256)算法

算法代码如下:

#include <openssl/sha.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>

// 将字节数组转换为十六进制字符串
// 将字节数组转换为十六进制字符串
std::string bytesToHex(const unsigned char* bytes, size_t length) {
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (size_t i = 0; i < length; ++i) {
        ss << std::setw(2) << (int)bytes[i];
    }
    return ss.str();
}

int main() {
    // 原数据
    const std::string data = "6572B36A91E28FB900134C3010C445437DC04D04";
    
    // 创建一个SHA256上下文
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    
    // 更新上下文以包含要哈希的数据
    SHA256_Update(&sha256, data.c_str(), data.size());
    
    // 计算哈希值
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_Final(hash, &sha256);
    
    // 将哈希值转换为十六进制字符串并输出
    std::string hashHex = bytesToHex(hash, SHA256_DIGEST_LENGTH);
    std::cout << "SHA256 hash: " << hashHex << std::endl;
    
    return 0;
}

运行结果如下:

HMAC_SHA256 算法

 算法代码如下:

#include <openssl/hmac.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>

// 将字节数组转换为十六进制字符串
std::string bytesToHex(const unsigned char* bytes, size_t length) {
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (size_t i = 0; i < length; ++i) {
        ss << std::setw(2) << (int)bytes[i];
    }
    return ss.str();
}

int main() {
    // 要进行HMAC的数据
    const std::string data = "374D34303534424E39323330351000FFFFFFFFFF";
    // HMAC的密钥
    const std::string key = "c0df3585876ac6bb02bf6347b3654993";
    
    // 输出缓冲区
    unsigned char* hmacResult = new unsigned char[EVP_MAX_MD_SIZE];
    unsigned int hmacLen = 0;
    
    // 使用HMAC_SHA256进行计算
    HMAC_CTX* hmacCtx = HMAC_CTX_new();
    HMAC_Init_ex(hmacCtx, key.data(), key.size(), EVP_sha256(), NULL);
    HMAC_Update(hmacCtx, (unsigned char*)data.data(), data.size());
    HMAC_Final(hmacCtx, hmacResult, &hmacLen);
    
    // 将HMAC结果转换为十六进制字符串并输出
    std::string hmacHex = bytesToHex(hmacResult, hmacLen);
    std::cout << "HMAC_SHA256: " << hmacHex << std::endl;
    
    // 清理资源
    HMAC_CTX_free(hmacCtx);
    delete[] hmacResult;
    
    return 0;
}

 执行结果如下:

 ECDH算法

        这个算法没有找到网页端的在线工具验证,但是笔者根据我们这次给的案例验证如下:

笔者感觉上述给的最终生成的会话秘钥应该有问题,生成的会话秘钥应该是256bit。

算法代码如下:

#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;

// 辅助函数,用于将十六进制字符串转换为 BIGNUM
BIGNUM* hex_to_BN(const std::string& hex) {
    BIGNUM* bn = BN_new();
    if (!BN_hex2bn(&bn, hex.c_str())) {
        BN_free(bn);
        throw std::runtime_error("Failed to convert hex to BIGNUM");
    }
    return bn;
}

// 辅助函数,用于打印会话密钥
void print_session_key(const unsigned char* key, size_t key_len) {
    std::stringstream ss;
    ss << "Session Key: ";
    for (size_t i = 0; i < key_len; ++i) {
        ss << std::hex << std::setw(2) << std::setfill('0') << (int)key[i];
    }
    std::cout << ss.str() << std::endl;
}

int main() {
	
    // 私钥十六进制串
    std::string privateKeyHex = "5904507894591f4b39308a51d5e2e25566a66366b1d6d952fba17de3af19235f";
    // 对端公钥十六进制串
    std::string publicKeyHex = "04fef2f1a2a0df9f75cda6e36268b7f62749cae378b7a5b9f311add58beaeadf3e49e41ac2acede766a21feaf354119f70ec3587f1054a1286ba08a1d866ef40ed";

    // 创建 EC_KEY 对象,使用 secp256r1 曲线
    EC_KEY* eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    if (!eckey) {
        std::cerr << "Error creating EC key with secp256r1 curve" << std::endl;
        return 1;
    }
	
    // 设置私钥
    BIGNUM* privateKeyBN = hex_to_BN(privateKeyHex);
	
    if (!EC_KEY_set_private_key(eckey, privateKeyBN)) {
        std::cerr << "Error setting private key" << std::endl;
        BN_free(privateKeyBN);
        EC_KEY_free(eckey);
        return 1;
    }
    BN_free(privateKeyBN); // EC_KEY_set_private_key 会复制 BN,所以可以安全释放

    // 解析对端公钥
    const EC_GROUP* group = EC_KEY_get0_group(eckey);
    EC_POINT* pubKeyPoint = EC_POINT_new(group);
    if (!EC_POINT_hex2point(group, publicKeyHex.c_str(), pubKeyPoint, NULL)) {
        std::cerr << "Error parsing public key" << std::endl;
        EC_POINT_free(pubKeyPoint);
        EC_KEY_free(eckey);
        return 1;
    }

    // 执行 ECDH 密钥交换
    unsigned char* session_key1 = (unsigned char*)OPENSSL_malloc(32);
	if (session_key1 == NULL) {
        std::cerr << "Error allocating memory for session keys" << std::endl;
        OPENSSL_free(session_key1);
        EC_KEY_free(eckey);
        return 1;
    }
	
	int ret = ECDH_compute_key(session_key1, 32, pubKeyPoint, eckey, NULL);
    if (ret < 0) {
        std::cerr << "Error computing shared secret" << std::endl;
        OPENSSL_free(session_key1);
        EC_POINT_free(pubKeyPoint);
        EC_KEY_free(eckey);
        return 1;
    }

    // 将共享密钥转换为十六进制字符串并打印
     print_session_key(session_key1, 32);

    // 清理资源
    OPENSSL_free(session_key1);
    EC_POINT_free(pubKeyPoint);
    EC_KEY_free(eckey);

    return 0;
}

执行结果为:

 ECC签名算法

算法代码如下:

#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <iostream>
#include <vector>
#include <cstring>

// 将十六进制字符串转换为字节数组
std::vector<unsigned char> hex2bytes(const std::string& hex) {
    std::vector<unsigned char> bytes;
    for (size_t i = 0; i < hex.length(); i += 2) {
        std::string byteString = hex.substr(i, 2);
        unsigned char byte = (unsigned char) strtol(byteString.c_str(), nullptr, 16);
        bytes.push_back(byte);
    }
    return bytes;
}

// 验证ECDSA签名
bool verify_ecdsa_signature(const std::string& public_key_hex, const std::string& data_hex, const std::string& signature_hex) {
    // 将十六进制字符串转换为字节数组
    std::vector<unsigned char> public_key_bytes = hex2bytes(public_key_hex);
    std::vector<unsigned char> data_bytes = hex2bytes(data_hex);
    std::vector<unsigned char> signature_bytes = hex2bytes(signature_hex);

    // 创建EC_KEY对象
    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    if (!ec_key) {
        std::cerr << "Failed to create EC_KEY" << std::endl;
        return false;
    }

    // 从字节数组中解析公钥
    const unsigned char* p = public_key_bytes.data();
    ec_key = o2i_ECPublicKey(&ec_key, &p, public_key_bytes.size());
    if (!ec_key) {
        std::cerr << "Failed to parse public key" << std::endl;
        EC_KEY_free(ec_key);
        return false;
    }

    // 计算数据的哈希值(假设使用SHA-256)
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, data_bytes.data(), data_bytes.size());
    SHA256_Final(hash, &sha256);

    // 验证签名
    ECDSA_SIG* ec_sig = ECDSA_SIG_new();
    const unsigned char* sig = signature_bytes.data();
    ec_sig = d2i_ECDSA_SIG(&ec_sig, &sig, signature_bytes.size());
    if (!ec_sig) {
        std::cerr << "Failed to parse signature" << std::endl;
        EC_KEY_free(ec_key);
        return false;
    }

    int verify_result = ECDSA_do_verify(hash, SHA256_DIGEST_LENGTH, ec_sig, ec_key);
    if (verify_result != 1) {
        std::cerr << "Signature verification failed" << std::endl;
        ECDSA_SIG_free(ec_sig);
        EC_KEY_free(ec_key);
        return false;
    }

    // 释放资源
    ECDSA_SIG_free(ec_sig);
    EC_KEY_free(ec_key);

    return true;
}

int main() {
    // 公钥、数据和签名的十六进制字符串
    std::string public_key_hex = "0467BF4978CB114972AE0AF84E22FD4099D1FF045F88830C41D9AC5CC4B4EBA17F8D1AB65884368BD47E1EF8A28A33EEE92BB6409AFB5217E0F120866B85913E0B";
    std::string data_hex = "03";
    std::string signature_hex = "3044022023FAE603D8A64BF004DCC56BCFD904F2E2E4AFCBD9DDF1F2C6F4EE1A4D7A1F3C0220708D8D63FBCD6BCA61B8827280F628074759C77104952307DD9C407F5B0B2C2D";

    // 验证签名
    bool is_valid = verify_ecdsa_signature(public_key_hex, data_hex, signature_hex);
    if (is_valid) {
        std::cout << "Signature is valid" << std::endl;
    } else {
        std::cout << "Signature is invalid" << std::endl;
    }

    return 0;
}

执行结果如下:

AES/CBC128算法 

 算法代码如下:

#include <openssl/aes.h>
#include <iostream>
#include <cstring>

// 假设你的数据长度总是16字节的倍数
void aes_cbc_128_encrypt_nopadding(const unsigned char* key, unsigned char* iv,
                                   const unsigned char* input, unsigned char* output, size_t length) {
    AES_KEY aesKey;
    AES_set_encrypt_key(key, 256, &aesKey); // 设置256位AES加密密钥

    // 由于我们假设输入数据长度是16字节的倍数,我们可以直接加密
    for (size_t i = 0; i < length; i += AES_BLOCK_SIZE) {
        AES_cbc_encrypt(input + i, output + i, AES_BLOCK_SIZE, &aesKey, iv, AES_ENCRYPT);
        // 更新IV,对于CBC模式,每个块的IV是上一个块的密文
        std::memcpy(iv, output + i, AES_BLOCK_SIZE);
    }
}

// 解密函数,使用256位AES密钥和CBC模式
void aes_cbc_128_decrypt_nopadding(const unsigned char* key, const unsigned char* iv,
                         const unsigned char* input, unsigned char* output, size_t length) {
    AES_KEY aesKey;
    AES_set_decrypt_key(key, 256, &aesKey);
    // 在CBC模式下,解密时需要一个临时的IV,因为它会在解密过程中被更新
    unsigned char temp_iv[AES_BLOCK_SIZE];
    std::memcpy(temp_iv, iv, AES_BLOCK_SIZE);
    for (size_t i = 0; i < length; i += AES_BLOCK_SIZE) {
        AES_cbc_encrypt(input + i, output + i, AES_BLOCK_SIZE, &aesKey, temp_iv, AES_DECRYPT);
        // 更新临时IV为下一个块的密文(实际上是上一个块的明文)
        std::memcpy(temp_iv, input + i, AES_BLOCK_SIZE);
    }
}

// 将十六进制字符串转换为字节数组
std::string hex2str(const std::string& hex) {
    std::string retStr;
    for (size_t i = 0; i < hex.length(); i += 2) {
        std::string byteString = hex.substr(i, 2);
        unsigned char byte = (unsigned char) strtol(byteString.c_str(), nullptr, 16);
        retStr += byte;
    }
    return retStr;
}

int main() {
    // 256位(32字节)的AES密钥
	const std::string keyhex = "c5ba9981452fa728a10794730919aaa747ca54df2f21fab685bbd0fdb53f05fb";
    const std::string keystr = hex2str(keyhex);
    // 初始化向量(IV),需要与密钥长度相同,即16字节
    unsigned char iv[AES_BLOCK_SIZE] = {0x00};

    // 要加密的数据(确保长度是16字节的倍数)
	const std::string plaintexthex = "313131313131313131313131313131313232323232323232323232323232323230450221009F9B7BC16546FDFA85866AFE2761FAF6C1B018C99E6B7C6339FF47BA126E01990220558339565F469C3AD4EBA77AEE5C22C7C464449D6395FBC1158F1B589569336980000000000000000000000000000000000000000000000000";
	
    const std::string plaintext = hex2str(plaintexthex); // 正好是16字节
    unsigned char input[plaintext.size()], key[2 * AES_BLOCK_SIZE];
    std::copy(plaintext.begin(), plaintext.end(), input);
	std::copy(keystr.begin(), keystr.end(), key);

    // 输出缓冲区
    unsigned char output[plaintext.size()];
	unsigned char in2put[plaintext.size()];

    // 调用加密函数
    aes_cbc_128_encrypt_nopadding(key, iv, input, output, plaintext.size());

    // 输出加密后的数据(以十六进制形式)
	std::cout << "加密数据 :";
    for (size_t i = 0; i < plaintext.size(); ++i) {
        printf("%02x", output[i]);
    }
    std::cout << std::endl;
	
	memset(iv, 0, AES_BLOCK_SIZE);
	// 调用解密函数
    aes_cbc_128_decrypt_nopadding(key, iv, output, in2put, plaintext.size());
	
	// 输出加密后的数据(以十六进制形式)
	std::cout << "解密数据 :";
    for (size_t i = 0; i < plaintext.size(); ++i) {
        printf("%02x", in2put[i]);
    }
    std::cout << std::endl;

    return 0;
}

执行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/972635.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RTSP协议讲解及漏洞挖掘

文章目录 前言一、RTSP协议简介二、RTSP协议常见应用场景包括三、攻击RTSP协议的好处四、RTSP多种认证模式五、工具使用下载地址六、RTSP协议漏洞挖掘手法 前言 实时流传输协议&#xff08;Real Time Streaming Protocol&#xff0c;RTSP&#xff09;&#xff0c;RFC2326&…

Mysql各操作系统安装全详情

" 至高无上的命运啊~ " MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Mana…

Elasticsearch7.1.1 配置密码和SSL证书

生成SSL证书 ./elasticsearch-certutil ca -out config/certs/elastic-certificates.p12 -pass 我这里没有设置ssl证书密码&#xff0c;如果需要设置密码&#xff0c;需要再配置给elasticsearch 在之前的步骤中&#xff0c;如果我们对elastic-certificates.p12 文件配置了密码…

EasyExcel 自定义头信息导出

需求&#xff1a;需要在导出 excel时&#xff0c;合并单元格自定义头信息(动态生成)&#xff0c;然后才是字段列表头即导出数据。 EasyExcel - 使用table去写入&#xff1a;https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write#%E4%BD%BF%E7%94%A8table%E…

C++基础知识学习记录—模版和泛型编程

1、模板 概念&#xff1a; 模板可以让类或者函数支持一种通用类型&#xff0c;在编写时不指定固定的类型&#xff0c;在运行时才决定是什么类型&#xff0c;理论上讲可以支持任何类型&#xff0c;提高了代码的重用性。 模板可以让程序员专注于内部算法而忽略具体类型&#x…

Django 连接(sqlserver)数据库方法

文章目录 django 的SQL server适配器&#xff0c;例如django-pyodbc-azure 或 mssql-django1、django-pyodbc-azure2、mssql-django3、注意 Django只内置了几个 Database Backend&#xff08;mysql、oracle、sqllite3&#xff08;默认&#xff09;、postgresql_psycopg2&#x…

华为 eNSP:MSTP

一、MSTP是什么 MSTP是多业务传送平台&#xff08;Multi-Service Transport Platform&#xff09;的缩写&#xff0c;它是一种基于SDH&#xff08;同步数字体系&#xff09;技术的传输网络技术&#xff0c;用于同时实现TDM、ATM、以太网等多种业务的接入、处理和传送。 MSTP技…

Mac端homebrew安装配置

拷打了一下午o3-mini-high&#xff0c;不如这位博主的超强帖子&#xff0c;10分钟结束战斗 跟随该文章即可&#xff0c;2025/2/19亲测可行 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客文章浏览阅读10w次&#xff0c;点赞258次&#xff0c;收藏837次。一直觉得自己写…

一台服务器将docker image打包去另一天服务器安装这个镜像

一台服务器将docker image打到去另一天服务器安装这个镜像 1. 打包2.另一台服务器执行 1. 打包 docker save -o nebula-graph-studio.tar harbor1.vm.example.lan/dockerio/vesoft/nebula-graph-studioxxx.tar 是打包好的文件 后面的是 docker image 2.另一台服务器执行 docke…

Web开发技术概述

Web开发技术涵盖了前端和后端开发&#xff0c;以及数据库技术。前端开发包括使用HTML、CSS、JavaScript等原生技术&#xff0c;以及jQuery、Bootstrap、AngularJS、React、Vue等框架。后端开发则涉及ASP.NET、PHP、Python Web&#xff08;Flask、Django&#xff09;、Java Web&…

【项目日记】仿RabbitMQ实现消息队列 --- 模块设计

你要的答案不在书本里&#xff0c; 也不能靠别人来解决&#xff0c; 除非你想一辈子当小孩。 你必须在自我内部找到答案&#xff0c; 感受到该做的正确事情。 --- 《献给阿尔吉侬的花束》--- 仿RabbitMQ实现消息队列 1 数据管理模块1.1 交换机数据管理模块1.2 队列数据管…

C++ Primer 构造函数再探

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

SQL 注入攻击详解[基础篇]:Web 应用程序安全漏洞与防御策略

目录 SQL注入的简介 现代 Web 应用程序中的数据库交互与 SQL 注入攻击 数据库管理系统&#xff08;DBMS&#xff09;架构与 SQL 注入 什么是 SQL 注入&#xff1f; SQL 注入的工作原理 SQL 注入的用例与影响 如何预防 SQL 注入&#xff1f; 数据库分类 数据库类型&am…

自制AirTag,支持安卓/鸿蒙/PC/Home Assistant,无需拥有iPhone

苹果的AirTag很贵&#xff0c;虽然某强北有平价代替品&#xff0c;但是仍需要苹果设备才能绑定&#xff0c;才能查看位置。不支持安卓/鸿蒙/PC&#xff0c;也不支持集成到Home Assistant中。 AirTag 的原理 每个AirTag都会发送一个蓝牙信号&#xff0c;其可以被临近的苹果设备…

网络技术变迁:从IPv4走向IPv6

目录 前言 旧时代产物&#xff1a;IPv4 什么是IPv4&#xff1f; IPv4的工作方式 IPv4的缺点 为什么要从IPv4过渡到IPv6&#xff1f; 走向IPv6&#xff1a;新一代互联网协议 IPv6的技术特性 我们需要过渡技术 双栈&#xff08;Dual Stack&#xff09; 隧道技术&#…

uniapp 滚动尺

scale组件代码&#xff08;部分class样式使用到了uview1.0的样式&#xff09; <template><view><view class"scale"><view class"pointer u-flex-col u-col-center"><u-icon name"arrow-down-fill" size"26&qu…

模型量化初始知识

原文网址&#xff1a;知乎原文-量化基础知识 背景 PyTorch对量化的支持目前有如下三种方式&#xff1a; Post Training Dynamic Quantization&#xff0c;模型训练完毕后的动态量化&#xff1b; Post Training Static Quantization&#xff0c;模型训练完毕后的静态量化&…

在项目中调用本地Deepseek(接入本地Deepseek)

前言 之前发表的文章已经讲了如何本地部署Deepseek模型&#xff0c;并且如何给Deepseek模型投喂数据、搭建本地知识库&#xff0c;但大部分人不知道怎么应用&#xff0c;让自己的项目接入AI模型。 文末有彩蛋哦&#xff01;&#xff01;&#xff01; 要接入本地部署的deepsee…

Redis7——基础篇(五)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…

【爬虫基础】第一部分 网络通讯 P1/3

前言 1.知识点碎片化&#xff1a;每个网站实现的技术相似但是有区别&#xff0c;要求我们根据不同的网站使用不同的应对手段。主要是常用的一些网站爬取技术。 2.学习难度&#xff1a;入门比web简单&#xff0c;但后期难度要比web难&#xff0c;在于爬虫工程师与网站开发及运维…