微信 MMTLS 协议详解(五):加密实现

常用的解密算法,对称非对称 加密,密钥协商, 带消息认证的加解密
#生成RSA 密钥对

void GenerateRsaKeypair(std::string& public_key,std::string& private_key)
{RSA* rsa = RSA_new();BIGNUM* bn = BN_new();// 生成 RSA 密钥对BN_set_word(bn, RSA_F4);RSA_generate_key_ex(rsa, 2048, bn, nullptr);// 创建内存 BIO 用于存储密钥BIO* bio_private = BIO_new(BIO_s_mem());BIO* bio_public = BIO_new(BIO_s_mem());// 将私钥写入 BIO(PKCS#8 格式)PEM_write_bio_RSAPrivateKey(bio_private, rsa, nullptr, nullptr, 0, nullptr,nullptr);// 将公钥写入 BIO(X.509 格式)PEM_write_bio_RSAPublicKey(bio_public, rsa);// 从 BIO 提取字符串char* priv_data = nullptr;char* pub_data = nullptr;long priv_len = BIO_get_mem_data(bio_private, &priv_data);long pub_len = BIO_get_mem_data(bio_public, &pub_data);private_key = std::string(priv_data, priv_len);public_key = std::string(pub_data, pub_len);// 释放资源BIO_free_all(bio_private);BIO_free_all(bio_public);RSA_free(rsa);BN_free(bn);
}

RSA 公钥加密

// 公钥加密
std::string EncryptWithPublic(const std::string& plaintext,const std::string& public_key) {BIO* bio = BIO_new_mem_buf(public_key.c_str(), -1);RSA* rsa = PEM_read_bio_RSAPublicKey(bio, nullptr, nullptr, nullptr);BIO_free_all(bio);if (!rsa) {return "";}int rsa_size = RSA_size(rsa);int max_plaintext_len =rsa_size - 42;  // RSA_PKCS1_OAEP_PADDING 填充后最大明文长度std::string encrypted_str;for (size_t i = 0; i < plaintext.length(); i += max_plaintext_len) {size_t len =std::min(max_plaintext_len, static_cast<int>(plaintext.length() - i));unsigned char* encrypted = new unsigned char[rsa_size];int result = RSA_public_encrypt(len, reinterpret_cast<const unsigned char*>(plaintext.c_str() + i),encrypted, rsa, RSA_PKCS1_OAEP_PADDING);if (result == -1) {RSA_free(rsa);delete[] encrypted;return "";}encrypted_str.append(reinterpret_cast<char*>(encrypted), result);delete[] encrypted;}RSA_free(rsa);return encrypted_str;
}

RSA 私钥解密


// 私钥解密
std::string DecryptWithPrivate(const std::string& ciphertext,const std::string& private_key) {BIO* bio = BIO_new_mem_buf(private_key.c_str(), -1);RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr);BIO_free_all(bio);if (!rsa) {return "";}int rsa_size = RSA_size(rsa);std::string decrypted_str;for (size_t i = 0; i < ciphertext.length(); i += rsa_size) {unsigned char* decrypted = new unsigned char[rsa_size];int result = RSA_private_decrypt(rsa_size,reinterpret_cast<const unsigned char*>(ciphertext.c_str() + i),decrypted, rsa, RSA_PKCS1_OAEP_PADDING);if (result == -1) {RSA_free(rsa);delete[] decrypted;return "";}decrypted_str.append(reinterpret_cast<char*>(decrypted), result);delete[] decrypted;}RSA_free(rsa);return decrypted_str;
}

生成ECDH 密钥对

#include <openssl/digest.h>
#include <openssl/ecdh.h>
#include <openssl/ec_key.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/sha.h>
#include <openssl/cipher.h>
#include <openssl/bio.h>
#include <openssl/md5.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
bool GenECDHKeypair(int nid,std::string& public_key,std::string& private_key) {bool ret = false;EC_KEY* ec_key = nullptr;unsigned char* pub_key_buf = nullptr;unsigned char* pri_key_buf = nullptr;do {ec_key = EC_KEY_new_by_curve_name(nid);if (!ec_key) {break;}EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);ret = EC_KEY_generate_key(ec_key);if (ret != 1) {break;}int pub_key_size = i2o_ECPublicKey(ec_key, &pub_key_buf);if (pub_key_size == 0 || !pub_key_buf) {break;}int pri_key_size = i2d_ECPrivateKey(ec_key, &pri_key_buf);if (pri_key_size == 0 || !pri_key_buf) {break;}public_key.assign((const char*)pub_key_buf, pub_key_size);private_key.assign((const char*)pri_key_buf, pri_key_size);ret = true;} while (false);if (ec_key) {EC_KEY_free(ec_key);}if (pub_key_buf) {OPENSSL_free(pub_key_buf);}if (pri_key_buf) {OPENSSL_free(pri_key_buf);}return ret;
}

生成ECDSA 密钥对


bool GenECDSAKeypair(int nid,std::string& public_key,std::string& private_key) {bool result = false;EC_KEY* ec_key = nullptr;BIO* bio = nullptr;do {ec_key = EC_KEY_new_by_curve_name(nid);if (!ec_key) {break;}EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);int ret = EC_KEY_generate_key(ec_key);if (ret != 1) {break;}ret = EC_KEY_check_key(ec_key);if (ret != 1) {break;}bio = BIO_new(BIO_s_mem());ret = PEM_write_bio_EC_PUBKEY(bio, ec_key);if (ret != 1 || BIO_flush(bio) != 1) {break;}char* ptr = nullptr;long size = BIO_get_mem_data(bio, &ptr);public_key.assign(ptr, size);BIO_free(bio);bio = BIO_new(BIO_s_mem());ret = PEM_write_bio_ECPrivateKey(bio, ec_key, nullptr, nullptr, 0, nullptr,nullptr);if (ret != 1 || BIO_flush(bio) != 1) {break;}ptr = nullptr;size = BIO_get_mem_data(bio, &ptr);private_key.assign(ptr, size);result = true;} while (false);if (nullptr != bio) {BIO_free(bio);}if (nullptr != ec_key) {EC_KEY_free(ec_key);}return result;
}

生成RSA 密钥对


bool GenRsaKeypair(std::string& public_key, std::string& private_key)
{// 产生RSA密钥RSA* rsa = RSA_new();BIGNUM* bn = BN_new();BN_set_word(bn, RSA_F4);RSA_generate_key_ex(rsa, 1024, bn, NULL);// 提取私钥BIO* bio_private = BIO_new(BIO_s_mem());PEM_write_bio_RSAPrivateKey(bio_private, rsa, NULL, NULL, 0, NULL, NULL);int private_key_len = BIO_pending(bio_private);char* pem_private_key = (char*)calloc(private_key_len + 1, 1);BIO_read(bio_private, pem_private_key, private_key_len);private_key.assign(pem_private_key, private_key_len);free(pem_private_key);BIO_free(bio_private);// 提取公钥BIO* bio_public = BIO_new(BIO_s_mem());PEM_write_bio_RSA_PUBKEY(bio_public, rsa);int public_key_len = BIO_pending(bio_public);char* pem_public_key = (char*)calloc(public_key_len + 1, 1);BIO_read(bio_public, pem_public_key, public_key_len);public_key.assign(pem_public_key, public_key_len);free(pem_public_key);BIO_free(bio_public);// 释放资源RSA_free(rsa);BN_free(bn);return true;
}

SHA256 ECDH 密钥协商

inline void* Sha256(const void* in,size_t in_len,void* out,size_t* out_len) {*out_len = SHA256_DIGEST_LENGTH;return SHA256((const uint8_t*)in, in_len, (uint8_t*)out);
}bool SHA256ECDH(int nid,const std::string& public_key,const std::string& private_key,std::string& result) {bool ret = false;EC_KEY* pub_ec_key = nullptr;EC_KEY* pri_ec_key = nullptr;do {pub_ec_key = EC_KEY_new_by_curve_name(nid);if (!pub_ec_key) {break;}auto uint8_pubkey = (const uint8_t*)public_key.data();pub_ec_key = o2i_ECPublicKey(&pub_ec_key, &uint8_pubkey, public_key.size());if (!pub_ec_key) {break;}pri_ec_key = EC_KEY_new_by_curve_name(nid);if (!pri_ec_key) {break;}auto uint8_privkey = (const uint8_t*)private_key.data();pri_ec_key = d2i_ECPrivateKey(&pri_ec_key, &uint8_privkey, private_key.size());if (!pri_ec_key) {break;}result.resize(SHA256_DIGEST_LENGTH);ECDH_compute_key(result.data(), SHA256_DIGEST_LENGTH,EC_KEY_get0_public_key(pub_ec_key), pri_ec_key, Sha256);ret = true;} while (false);// free memoryif (pub_ec_key) {EC_KEY_free(pub_ec_key);}if (pri_ec_key) {EC_KEY_free(pri_ec_key);}return ret;
}

MD5 ECDH 密钥协商

inline void* MD5(const void* in,size_t in_len,void* out,size_t* out_len) {*out_len = MD5_DIGEST_LENGTH;MD5_CTX ctx;MD5_Init(&ctx);MD5_Update(&ctx, in, in_len);MD5_Final((uint8_t*)out, &ctx);return out;
}bool MD5ECDH(int nid,const std::string& public_key,const std::string& private_key,std::string& result) {bool ret = false;EC_KEY* pub_ec_key = nullptr;EC_KEY* pri_ec_key = nullptr;do {pub_ec_key = EC_KEY_new_by_curve_name(nid);if (!pub_ec_key) {break;}auto uint8_pubkey = (const uint8_t*)public_key.data();pub_ec_key = o2i_ECPublicKey(&pub_ec_key, &uint8_pubkey, public_key.size());if (!pub_ec_key) {break;}pri_ec_key = EC_KEY_new_by_curve_name(nid);if (!pri_ec_key) {break;}auto uint8_privkey = (const uint8_t*)private_key.data();pri_ec_key = d2i_ECPrivateKey(&pri_ec_key, &uint8_privkey, private_key.size());if (!pri_ec_key) {break;}result.resize(MD5_DIGEST_LENGTH);ECDH_compute_key(result.data(), MD5_DIGEST_LENGTH,EC_KEY_get0_public_key(pub_ec_key), pri_ec_key, MD5);   ret = true;} while (false);// free memoryif (pub_ec_key) {EC_KEY_free(pub_ec_key);}if (pri_ec_key) {EC_KEY_free(pri_ec_key);}return ret;
}

AES256GCM 加密


std::string Aes256GcmEncrypt(const void* once,int32_t once_len,const void* key,int32_t key_len,const void* aad,int32_t aad_len,const void* data,int32_t data_len,int tag_size,std::string& tag) {std::string result;EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();EVP_CIPHER_CTX_init(ctx);EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);do {// set iv sizeint ret =EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, once_len, nullptr);if (ret != 1) {break;}ret = EVP_EncryptInit_ex(ctx, nullptr, nullptr, (const uint8_t*)key,(const uint8_t*)once);if (ret != 1) {break;}int out_len = 0;if (aad_len != 0) {ret = EVP_EncryptUpdate(ctx, nullptr, &out_len,(const uint8_t*)aad, aad_len);if (ret != 1) {break;}}result.resize(EVP_CIPHER_CTX_block_size(ctx) + data_len);int encrypt_len = 0;if (data_len != 0) {ret = EVP_EncryptUpdate(ctx, (uint8_t*)result.data(), &out_len,(const uint8_t*)data, data_len);if (ret != 1) {break;}encrypt_len = out_len;}ret = EVP_EncryptFinal_ex(ctx, (uint8_t*)result.data() + encrypt_len,&out_len);if (ret != 1) {break;}encrypt_len += out_len;result.resize(encrypt_len);if (tag_size != 0) {tag.resize(tag_size);ret =EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag.data());if (ret != 1) {break;}}} while (false);EVP_CIPHER_CTX_free(ctx);return result;
}

AES256 GCM 解密


std::string AesGcmDecrypt(const void* once,int32_t once_len,const void* key,int32_t key_len,const void* aad,int32_t aad_len,const void* tag,int32_t tag_len,const void* data,int32_t data_len) {std::string result;EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();EVP_CIPHER_CTX_init(ctx);EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);do {int ret =EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, once_len, nullptr);if (ret != 1) {break;}ret = EVP_DecryptInit_ex(ctx, nullptr, nullptr, (const uint8_t*)key,(const uint8_t*)once);if (ret != 1) {break;}int out_len = 0;// set aadif (aad_len != 0) {ret = EVP_DecryptUpdate(ctx, nullptr, &out_len,(const uint8_t*)aad, aad_len);if (ret != 1) {break;}}result.resize(EVP_CIPHER_CTX_block_size(ctx) + data_len);int decrypt_len = 0;if (data_len != 0) {ret = EVP_DecryptUpdate(ctx, (uint8_t*)result.data(), &out_len,(const uint8_t*)data, data_len);if (ret != 1) {break;}decrypt_len = out_len;}ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len,(void*)tag);if (ret == 1) {ret = EVP_DecryptFinal_ex(ctx, (uint8_t*)result.data() + decrypt_len,&out_len);if (ret == 1) {decrypt_len += out_len;result.resize(decrypt_len);} else {result.clear();}} else {result.clear();}} while (false);EVP_CIPHER_CTX_free(ctx);return result;
}

AES 加密


std::string AESEncrypt(const std::string& key,const void* data,int32_t data_len) {if ( 0 == data_len){return "";}// 计算paddingint padding = 16 - data_len % 16;std::string padding_data(data_len + padding, (char)padding);memcpy(padding_data.data(), data, data_len);uint8_t tmp_key[16] = {};uint8_t* ptmp_key = nullptr;if (key.length() == 16) {ptmp_key = (uint8_t*)key.data();}else {ptmp_key = tmp_key;memcpy(tmp_key, key.data(), key.length() > 16 ? 16 : key.length());}uint8_t iv[16] = {};memcpy(iv, ptmp_key, 16);std::string result(padding_data.size(), 0);AES_KEY aes_key;AES_set_encrypt_key(ptmp_key, 128, &aes_key);AES_cbc_encrypt((uint8_t*)padding_data.data(), (uint8_t*)result.data(),padding_data.length(), &aes_key, iv, AES_ENCRYPT);return result;
}

AES 解密


std::string AESDecrypt(const std::string& key, const void* data, int32_t len)
{if (key.empty() || len == 0) {return "";}uint8_t tmp_key[16] = {};uint8_t* ptmp_key = nullptr;if (key.length() == 16){ptmp_key = (uint8_t*)key.data();}else{ptmp_key = tmp_key;memcpy(tmp_key, key.data(), key.length() > 16 ? 16 : key.length());}uint8_t iv[16] = {};memcpy(iv, ptmp_key, 16);std::string result(len, 0);AES_KEY aes_key;AES_set_decrypt_key(ptmp_key, 128, &aes_key);AES_cbc_encrypt((uint8_t*)data, (uint8_t*)result.data(), len,&aes_key, iv, AES_DECRYPT);// 去掉paddingchar padding = result[result.length() - 1];if (padding > 0 && padding <= 16){result.resize(result.length() - padding);}return result;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HashMap学习总结——JDK17

文章目录 HashMap构造方法HashMap(int initialCapacity, float loadFactor)loadFactor 加载因子initialCapacity 初始容量tableSizeFor(int cap) 计算前导零 HashMap(Map<? extends K, ? extends V> m) put(K key, V value)hash(Object key) 求hash值putVal(int hash, …

Linux:进程信号

✨✨所属专栏&#xff1a;Linux✨✨ ✨✨作者主页&#xff1a;嶔某✨✨ Linux&#xff1a;进程信号 在讲信号之前&#xff0c;我们先来从生活中的事情来确定信号的一些特性。 我在网上买了商品&#xff0c;我在等快递。但是在快递没来之前我知道快递来的时候我应该怎么处理。…

c#知识点补充2

1.非静态类能否调用静态方法可以 2.对string类型扩展方法&#xff0c;如何进行 类用静态类&#xff0c;参数是this 调用如下 3.out的用法 一定要给a赋值 这种写法不行 这样才行 4.匿名类 5.委托的使用 无论是匿名委托&#xff0c;还是具命委托&#xff0c;委托实例化后一定要…

0322-数据库、前后端

前端 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>Insert title here</title> <script srcjs/jquery-3.7.1.min.js></script> <script> //jquaryajax发起请求 //传参形式不同 post用data{}…

Spring Boot02(数据库、Redis)02---java八股

MySQL和Redis的区别&#xff1f; 1. 数据类型&#xff1a; MySQL是一种关系型数据库&#xff0c;表结构化存储&#xff0c;使用 SQL 查询。支持表、列、行等结构化数据。 Redis是一种基于内存的缓存系统&#xff0c;支持多种数据结构&#xff0c;如字符串、哈希表、列表、集合、…

VulnHub-Web-Machine-N7通关攻略

一、信息收集 第一步&#xff1a;确定靶机IP为192.168.0.107 第二步&#xff1a;扫描后台及开放端口 第三步&#xff1a;进行敏感目录及文件扫描 http://192.168.0.107/index.html (CODE:200|SIZE:1620) http://192.168.0.107/server-status (CODE:403|SIZ…

【AI News | 20250322】每日AI进展

AI Repos 1、DeTikZify 可以把草图或图形转换成TikZ代码的模型&#xff0c;可用来绘制复杂的科学图表&#xff0c;输入草图或文字描述即可转换成TikZ代码。DeTikZify强大的地方在于它能理解图表的语义信息&#xff0c; 能识别图表中的不同组成部分及其含义&#xff0c;比如坐标…

三主热备架构

1.要求 角色主机名软件IP地址用户client192.168.72.90keepalivedvip192.168.72.100masterserverAkeepalived, nginx192.168.72.30backupserverBkeepalived, nginx192.168.72.31backupserverCkeepalived, nginx192.168.72.32webtomcat1tomcat192.168.72.41webtomcat2tomcat192.1…

LiteratureReading:[2023] GPT-4: Technical Report

文章目录 一、文献简明&#xff08;zero&#xff09;二、快速预览&#xff08;first&#xff09;1、标题分析2、作者介绍3、引用数4、摘要分析&#xff08;1&#xff09;翻译&#xff08;2&#xff09;分析 5、总结分析&#xff08;1&#xff09;翻译&#xff08;2&#xff09;…

java使用Apache POI 操作word文档

项目背景&#xff1a; 当我们对一些word文档&#xff08;该文档包含很多的标题比如 1.1 &#xff0c;1.2 &#xff0c; 1.2.1.1&#xff0c; 1.2.2.3&#xff09;当我们删除其中一项或者几项时&#xff0c;需要手动的对后续的进行补充。该功能主要是对标题进行自动的补充。 具…

OpenHarmony 开源鸿蒙北向开发——linux使用make交叉编译第三方库

这几天搞鸿蒙&#xff0c;需要编译一些第三方库到鸿蒙系统使用。 头疼死了&#xff0c;搞了一个多星期总算搞定了。 开贴记坑。 一、SDK下载 1.下载 在linux下使用命令 wget https://cidownload.openharmony.cn/version/Master_Version/OpenHarmony_5.1.0.54/20250313_02…

SVN简明教程——下载安装使用

SVN教程目录 一、开发中的实际问题二、简介2.1 版本控制2.2 Subversion2.3 Subversion的优良特性2.4 工作原理2.5 SVN基本操作 三、Subversion的安装与配置1. 服务器端程序版本2. 下载源码包3. 下载二进制安装包4. 安装5. 配置版本库① 为什么要配置版本库&#xff1f;② 创建目…

OpenCV旋转估计(1)用于估计图像间仿射变换关系的类cv::detail::AffineBasedEstimator

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 基于仿射变换的估计器。 这种估计器使用匹配器估算的成对变换来为每个相机估算最终的变换。 cv::detail::AffineBasedEstimator 是 OpenCV 库中…

大数据学习栈记——HBase安装

本文介绍大数据技术中流行的非关系型数据库HBase的安装&#xff0c;操作系统&#xff1a;Ubuntu24.04 安装Zookeeper 安装HBase前需要先安装Zookeeper&#xff0c;HBase使用Zookeeper作为其分布式协同服务&#xff0c;存储了HBase集群的元数据信息&#xff0c;并提供了分布式…

SpringBoot+VUE(Ant Design Vue)实现图片下载预览功能

目录 背景 1.后端实现下载接口 2.前端请求实现 第一步&#xff1a;导入api 第二步&#xff1a;请求接口 3.前端展示实现 4.实现效果展示 5.总结 背景 这段时间通过SpringBootVUE(Ant Design Vue)框架做了一个项目&#xff0c;但是在图片下载&#xff0c;展示的时候在网…

Java 推送钉钉应用消息

前言&#xff1a; 本文的目的是通过手机号获取钉钉成员的userid&#xff0c;实现钉钉应用的消息推送。 一、创建钉钉应用 登录钉钉开放平台 二、应用相关凭证 需要获取 Client ID (原 AppKey 和 SuiteKey) Client Secret (原 AppSecret 和 SuiteSecret) App ID 原企业内部…

SpringCloud介绍

什么是SpringCloud&#xff1f; SpringCloud 是分布式微服务架构下的一站式解决方案&#xff0c;是各个微服务架构落地技术的集合体&#xff0c;俗称微服务全家桶。 官方介绍&#xff1a; SpringCloud是基于SpringBoot提供了一套微服务解决方案&#xff0c;包括服务注册与发现…

YOLOv11 目标检测

本文章不再赘述anaconda的下载以及虚拟环境的配置&#xff0c;博主使用的python版本为3.8 1.获取YOLOv11的源工程文件 链接&#xff1a;GitHub - ultralytics/ultralytics: Ultralytics YOLO11 &#x1f680; 直接下载解压 2.需要自己准备的文件 文件结构如下&#xff1a;红…

【Linux】——环境变量与进程地址空间

文章目录 环境变量环境变量的概念常见的环境变量PATH相关指令 main的三个参数前两个参数第三个参数 程序地址空间进程地址空间 环境变量 环境变量的概念 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数&#xff0c;将来会以shell的形式传递给所有进程&…

Kafka--常见问题

1.为什么要使用 Kafka&#xff0c;起到什么作用 Kafka是一个高吞吐量、分布式、基于发布订阅的消息系统&#xff0c;它主要用于处理实时数据流 Kafka 设计上支持高吞吐量的消息传输&#xff0c;每秒可以处理数百万条消息。它能够在处理大量并发请求时&#xff0c;保持低延迟和…