Qt/C++ 解决调用国密SM3,SM4加密解密字符串HEX,BASE64格式转换和PKCS5Padding字符串填充相关问题

项目中遇到了需要与JAVA WEB接口使用SM3,SM4加密数据对接的需求,于是简单了解了下SM3与SM4加密算法在C++环境下的实现。并使用Qt/C++还原了在线SM3国密加密工具和在线SM4国密加密解密工具网页的示例功能的实现

目录导读

  • 前言
    • SM3算法简介
    • SM4算法简介
  • 实现示例
    • 字符串HEX,BASE64格式转换
      • 使用CryptBinaryToString 函数
      • 使用QByteArray类中的静态函数
    • 使用PKCS5Padding标准填充
    • 代码示例

前言

简单介绍下SM3,SM4的C++算法

  • SM3算法简介

SM3是中华人民共和国政府采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。
在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。
摘要出自:在线SM3国密加密工具

  • SM3加密C++代码实现:

SM3密码杂凑算法 国密pdf文件说明 文档看着也比较头疼,这里直接借鉴使用 SM3算法C语言实现-下载中的代码,实测没任何问题,这里不贴出代码,如有需要请前往下载。

  • 参考文章:

国密SM3杂凑算法与实现
SM3算法C语言实现-下载
国密SM3算法在linux和windows平台结果不一致问题
sm3算法实现
SM3密码杂凑算法 国密pdf文件说明


SM4算法简介

SM4.0(原名SMS4.0)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”。
在商用密码体系中,SM4主要用于数据加密,其算法公开,分组长度与密钥长度均为128bit,加密算法与密钥扩展算法都采用32轮非线性迭代结构,S盒为固定的8比特输入8比特输出。
SM4.0中的指令长度被提升到大于64K(即64×1024)的水平,这是SM 3.0规格(渲染指令长度允许大于512)的128倍。
摘要出自:在线SM4国密加密解密工具

  • SM4加密C++代码实现:

同样SM4的C++代码直接使用国密SM4分组加密算法实现 (C++)中实现的SM4源码,
可以直接在国密SM4分组加密算法实现 (C++)文章末尾下载,如有需要请前往下载。

  • 参考文章:

SM4国密算法实现分析
国密SM4分组加密算法实现 (C++)


实现示例

尝试使用Qt Creator 5.13.1 MSCV2017编写一个实现和在线SM4国密加密工具一样的功能的Demo,
整个样式也是借鉴的在线SM4国密加密工具界面样式。

  • 如下图示:

在这里插入图片描述
在这里插入图片描述

示例执行程序见文章附件资源;


在线SM4国密加密工具中的功能实现其实并不复杂,
SM3,SM4的C++算法实现都可以通过上面的链接下载后直接使用,
再通过HEX,BASE64字符串格式转换字符串填充就能直接输出一致的加密解密内容

  • 字符串HEX,BASE64格式转换

在进行数据加密的时候需要将PBYTE(unsigned char*)字符串转换为HEX(十六进制) 或者 Base64格式
一开始我是打算使用CryptBinaryToStringW函数进行转换,
后来发现QByteArray类能直接转换成HEX(十六进制)Base64格式字符串

  • 使用CryptBinaryToString 函数

CryptBinaryToString 函数将字节数组转换为格式化字符串。
传入PBYTE数据字符串并指定长度,
并输出标准化的HEX(16进制)或BASE64字符串

  • 语法:
BOOL CryptBinaryToStringW(//!指向要转换为字符串的字节数组的指针。[in]            const BYTE *pbBinary,//! pbBinary 数组中的元素数。[in]            DWORD      cbBinary,//! 指定生成的格式化字符串的格式 CRYPT_STRING_HEX or CRYPT_STRING_BASE64[in]            DWORD      dwFlags,//! 指向接收转换字符串的缓冲区的指针。 若要计算必须分配以保存返回的字符串的字符数,请将此参数设置为 NULL。 函数会将所需数量的字符(包括终止 NULL 字符)放在 pcchString 指向的值中[out, optional] LPWSTR     pszString,//! 指向 DWORD 变量的指针,该变量包含 pszString 缓冲区的大小(以 TCHAR为单位)。 如果 pszString 为 NULL,则函数计算返回字符串的长度, (包括 TCHARs 中的终止 null 字符) ,并在此参数中返回它。 如果 pszString 不为 NULL 且不够大,则该函数会将二进制数据转换为指定的字符串格式(包括终止 null 字符),但 pcchString 接收 TCHARs 的长度,不包括终止 null 字符。[in, out]       DWORD      *pcchString
);
  • C++代码示例:

引用头文件:

#include <Windows.h>
#include <wincrypt.h>
#include <string.h>
#include <stdio.h>
#pragma comment(lib, "Crypt32.lib")
class WinApi_Binary
{
public:WinApi_Binary();/** https://learn.microsoft.com/zh-cn/windows/win32/api/wincrypt/nf-wincrypt-cryptbinarytostringwCryptBinaryToStringW*///! 将PBYTE转换成十六进制字符串QString TO_HEX32(const BYTE * pbBinary);//! 将PBYTE转换成BASE64字符串QString TO_BASE64(const BYTE * pbBinary);private://! CryptBinaryToString 函数将字节数组转换为格式化字符串。//! https://learn.microsoft.com/zh-cn/windows/win32/api/wincrypt/nf-wincrypt-cryptbinarytostringwQString ToCryptBinaryToString(const BYTE *pbBinary,DWORD cbBinary,DWORD dwFlags);
};

具体实现:

WinApi_Binary::WinApi_Binary()
{
}
QString WinApi_Binary::ToCryptBinaryToString(const BYTE *pbBinary,DWORD cbBinary,DWORD dwFlags)
{DWORD pcchString=0;QString ValString="";if(CryptBinaryToStringW(pbBinary,cbBinary,dwFlags,NULL,&pcchString)){if(pcchString==0)return ValString;LPWSTR pszString=new TCHAR[pcchString];if(CryptBinaryToStringW(pbBinary,cbBinary,dwFlags,pszString,&pcchString)){ValString=QString::fromWCharArray(pszString);}delete pszString;pszString=nullptr;}return ValString;}QString WinApi_Binary::TO_HEX32(const BYTE * pbBinary)
{return  ToCryptBinaryToString(pbBinary,32,CRYPT_STRING_HEX|CRYPT_STRING_NOCRLF);
}QString WinApi_Binary::TO_BASE64(const BYTE * pbBinary)
{return  ToCryptBinaryToString(pbBinary,32,CRYPT_STRING_BASE64|CRYPT_STRING_NOCRLF);
}

CryptBinaryToStringW 转换字符串的使用还是过于繁琐了,使用Qt自带的QByteArray类转换字符串更快更方便;


  • 使用QByteArray类中的静态函数

使用
QByteArray::fromHex(Text.toLatin1())
QByteArray::fromBase64(Text.toLatin1())
获取base64,hex(16进制)格式数据;
使用
QByteArray((char*)DestBuffer,actualen).toHex().toUpper();
QByteArray((char*)DestBuffer,actualen).toBase64()
转换成字base64,hex(16进制)格式符串,
其中DestBuffer是PBYTE类型,actualen是字符长度;
使用QByteArray类进行字符串格式转换比较简单。直接可以转换成QString输出文本。


  • 使用PKCS5Padding标准填充

SM3加密不需要进行对字符串进行填充,
SM4加密时需要对字符串进行PKCS5Padding标准填充,否则计算除了的加密/解密字符串会与在线SM4国密加密工具计算出来的结果不一致。

在通过SM4加密与在线SM4国密加密工具计算出来的结果对比失败N次后才发现需要进行PKCS5Padding标准字符串填充,PKCS5Padding填充规则并不复杂:

PKCS5Padding:填充的原则是,如果长度少于16个字节,需要补满16个字节,补(16-len)个(16-len)例如:
huguozhen这个节符串是9个字节,16-9= 7,补满后如:huguozhen+7个十进制的7
如果字符串长度正好是16字节,则需要再补16个字节的十进制的16。
参考出自:关于C++和JAVA,AES/ECB/PKCS5Padding 互相通信的问题

  • C++代码实现:
//! input 需要填充的字符串
//! inputLen 字符串长度
//! actualen 填充后的字符串长度
//! 返回填充后的字符串
unsigned char * PKCS5Padding(unsigned char *input,int inputLen,int& actualen)
{actualen=0;int diff=0;if(inputLen%16==0){actualen=inputLen+16;diff=16;}else{int num= (int)ceil((double)inputLen/16.0);actualen=num*16;diff=actualen-inputLen;}qDebug()<<"[len] "<<inputLen<<" [actualen] "<<actualen<<" [diff] "<<diff;unsigned char * SrcBuffer=(unsigned char *)malloc(sizeof (unsigned char)*actualen);memset(SrcBuffer, diff, actualen);for(int i=0;i<inputLen;i++){SrcBuffer[i]=input[i];}return SrcBuffer;
}

SM4加密填充,解密后同样需要移除填充的内容:

因为加密时补的是十进制1到16,解密时,需要把这部分补位的去掉,判断要解密的字符串,每个字节是不是 char>=1 && char<= 16,如果是的话,就用0来替换以前的值,直到结束。
参考出自:关于C++和JAVA,AES/ECB/PKCS5Padding 互相通信的问题

通过上述对字符串进行HEX,BASE64格式转换再PKCS5Padding填充后,
加密/解密的结果基本就和在线SM4国密加密工具一致了。


  • 代码示例

这里简单演示调用上面的SM3和SM4加密的C++的代码示例;

  • SM3加密示例

使用libsm3.sm3(Data, Lens, OutText)直接调用加密,这是上面SM3加密C++ Demo中已经实现的方法,
使用QTextCodec进行文本字符串格式转换,测试使用Utf-8和Gb2312与在线工具输出一致。
使用QByteArray 输入输出HEX(16进制)或Base64格式数据

QString Operate_Command::SM3_Encrypt(QString Text,int TextType,QString codeType,int outType)
{QByteArray encodedData;switch (TextType) {case 0:{//! 文本QTextCodec * Codec=QTextCodec::codecForName(codeType.toStdString().c_str());qDebug()<<"Codec: "<<Codec->name();encodedData = Codec->fromUnicode(Text);break;}case 1:{//! HEXencodedData=QByteArray::fromHex(Text.toLatin1());break;}case 2:{//! BASE64encodedData=QByteArray::fromBase64(Text.toLatin1());break;}}Lib_SM3 libsm3;//! 字符长度int Lens=encodedData.size();PBYTE Data=(PBYTE)encodedData.data();PBYTE OutText=new BYTE[32];//! SM3加密libsm3.sm3(Data, Lens, OutText);// WinApi_Binary binary;QString middlekey="";//! 加密输出格式switch (outType) {case 0:{//! 输出 HEX 十六进制middlekey=QByteArray((char*)OutText,32).toHex().toUpper();break;}case 1:{//! 输出 base64格式middlekey=QByteArray((char*)OutText,32).toBase64();break;}}return middlekey;
}
  • SM4加密示例

使用SM4 ECB PKCS5Padding加密示例:
先使用sm4_setkey_enc函数设置密钥,
在通过PKCS5Padding填充字符串,
在使用sm4_crypt_ecb函数加密内容,

sm4_setkey_enc函数sm4_crypt_ecb函数是上面SM4加密C++ Demo中已经实现的方法,只需要调用。

代码示例:

QString Operate_Command::SM4_Encrypt_ECB(QString Key,int keyType,QString Text,int TextType,QString codeType,int outType)
{
qDebug()<<" --- --- ---> ";QByteArray encodedData;switch (TextType) {case 0:{//! 文本QTextCodec * Codec=QTextCodec::codecForName(codeType.toStdString().c_str());encodedData = Codec->fromUnicode(Text);break;}case 1:{//! HEXencodedData=QByteArray::fromHex(Text.toLatin1());break;}case 2:{//! BASE64encodedData=QByteArray::fromBase64(Text.toLatin1());break;}}qDebug("%s",encodedData.data());QByteArray keyData;switch (keyType) {case 0:{//! 文本QTextCodec * Codec=QTextCodec::codecForName(codeType.toStdString().c_str());keyData = Codec->fromUnicode(Key.mid(0,16));break;}case 1:{//! HEXkeyData=QByteArray::fromHex(Key.toLatin1());break;}case 2:{//! BASE64keyData=QByteArray::fromBase64(Key.toLatin1());break;}}qDebug("%s",keyData.data());int length=encodedData.size();PBYTE SrcBuffer=(PBYTE)encodedData.data();PBYTE keyBuffer=(PBYTE)keyData.data();Lib_SM4 libsm4;sm4_context ctx;//设置 加密秘钥libsm4.sm4_setkey_enc(&ctx,keyBuffer);//字符串填充int actualen=length;PBYTE ToPKCS5Pad=libsm4.PKCS5Padding(SrcBuffer,length,actualen);PBYTE DestBuffer=new BYTE[actualen];//加密libsm4.sm4_crypt_ecb(&ctx, 1, actualen, ToPKCS5Pad, DestBuffer); //1 为加密 0为解密QString middlekey="";//! 加密输出格式switch (outType) {case 1:{//! 输出 HEX 十六进制middlekey=QByteArray((char*)DestBuffer,actualen).toHex().toUpper();break;}case 0:case 2:{//! 输出 base64格式middlekey=QByteArray((char*)DestBuffer,actualen).toBase64();break;}}QString VStr="";QString SRCSTR="";for(int i=0;i<actualen;i++){VStr+=QString("%1").arg(DestBuffer[i],2,16,QLatin1Char('0'));SRCSTR+=QString("%1 ").arg(ToPKCS5Pad[i],2,16,QLatin1Char('0'));}qDebug()<<"[VStr] "<<VStr;qDebug()<<"[SRCSTR] "<<SRCSTR;delete DestBuffer;DestBuffer=nullptr;free(ToPKCS5Pad);return middlekey;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

气膜影院:沉浸式观影体验的全新选择—轻空间

随着观影需求的不断提升&#xff0c;传统影院形式已经无法满足观众对更高沉浸感和视觉体验的追求。气膜影院作为一种新兴的观影场所&#xff0c;以其独特的球幕结构和先进的技术手段&#xff0c;为观众带来了全新的沉浸式视听体验。 全景沉浸式观影体验 气膜影院采用球幕设计&a…

Awcing 799. 最长连续不重复子序列

Awcing 799. 最长连续不重复子序列 解题思路: 让我们找到一个数组中&#xff0c;最长的 不包含重复的数 的连续区间的长度。 最优解是双指针算法&#xff1a; 我们用 c n t [ i ] cnt[i] cnt[i]记录 i i i 这个整数在区间内出现的次数。(因为每个数的大小为 1 0 5 10^5 105, …

赵长鹏今日获释,下一步会做什么?币安透露2024年加密货币牛市的投资策略!

中国时间2024年9月28日&#xff0c;加密货币行业的风云人物赵长鹏&#xff08;Changpeng Zhao&#xff0c;简称CZ&#xff09;终于从监狱获释。他因在担任币安首席执行官期间未能有效执行反洗钱(AML)计划而被判刑四个月。赵长鹏的获释引发了广泛关注&#xff0c;不仅因为他是全…

大语言模型知识点分享

1 目前主流的开源模型体系有哪些&#xff1f; Prefix Decoder 系列模型 核心点&#xff1a; 输入采用双向注意力机制&#xff0c;输出为单向注意力。双向注意力意味着输入的每个部分都可以关注到输入的所有其他部分&#xff0c;这在理解上下文时具有很强的优势。 代表模型&a…

python全栈开发《41.列表的clear函数》

1.clear的功能 一次性将当前列表中所有的数据清空。 2.clear的用法 target [1,2,3,4,5,6] target.clear() print(target) 运行结果&#xff1a; /Users/llq/PycharmProjects/pythonlearn/pythonlearn/python_list/bin/python /Users/llq/PycharmProjects/pythonlearn/python_l…

JavaEE: 探索网络世界的核心-IP协议

文章目录 IP 协议协议头格式IP 地址IP地址的数量限制解决IP不够用的问题 IP 地址的网段划分子网掩码ABCDE五类网络 特殊的 IP 地址 IP 协议 协议头格式 4位版本号: 只有两个取值,4(IPv4)和6(IPv6). IPv2,IPv5这些在实际中是没有的,可能是理论上/实验室中存在~ 4位首部长度: IP…

Redis集群的两种方式

1.Redis集群 1.1 搭建主从集群 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写的分离。一般情况下&#xff0c;主节点负责写操作&#xff0c;从节点负责读操作。而从节点如何得知数据呢&#xff…

Study-Oracle-10-ORALCE19C-RAC集群搭建(一)

一、硬件信息及配套软件 1、硬件设置 RAC集群虚拟机:CPU:2C、内存:10G、操作系统:50G Openfile数据存储:200G (10G*2) 2、网络设置 主机名公有地址私有地址VIP共享存储(SAN)rac1192.168.49.13110.10.10.20192.168.49.141192.168.49.130rac2192.168.49.13210.10.10.3…

产品管理 - 互联网产品(4): 交互设计

原型设计 原型是产品可视化的展示&#xff0c;包括了产品的信息架构、功有、内容、交互方式。目前业务普遍菜用了Axure作为原型设计工具。产品或交互人员通过对信息架构的梳理&#xff0c;确认界面内容区的划分&#xff0c;并通过交互方式呈现功能点。 原型分为线框图、低保真…

如何通过Dockfile更改docker中ubuntu的apt源

首先明确我们有一个宿主机和一个docker环境&#xff0c;接下来的步骤是基于他们两个完成的 1.在宿主机上创建Dockerfile 随便将后面创建的Dockerfile放在一个位置,我这里选择的是 /Desktop 使用vim前默认你已经安装好了vim 2.在输入命令“vim Dockerfile”之后&#xff0c;…

留学生如何适应海外生活以及应对文化差异

对于即将出国学习和生活的留学生来说&#xff0c;文化差异和生活方式的变化常常是一个紧迫的问题。那么&#xff0c;如何应对这些文化差异&#xff0c;以及如何适应新的学习环境和社交生活呢&#xff1f;本文将分享一些具体可行的建议和方法&#xff0c;助您顺利跨越这道难关&a…

CentOS 替换 yum源 经验分享

视频教程在bilibili:CentOS 替换 yum源 经验分享_哔哩哔哩_bilibili问题原因 解决方法 1. 进入镜像目录 [rootlocalhost ~]# cd /etc/yum.repos.d/ 2.备份文件 [rootlocalhost yum.repos.d]# rename repo bak * 3.寻找阿里镜像源复制 https://developer.aliyun.com/mirror/ …

vue框架学习 -- 日历控件 FullCalendar 使用总结

最近在项目中要实现日期排班的功能&#xff0c;正好要用到日历视图的控件&#xff0c;经过对比发现&#xff0c;vue 中 使用 FullCalendar 可以实现相关需求&#xff0c;下面对使用过程做一个总结。 一. 引入 FullCalendar 控件 package.json 中添加相关依赖 "dependen…

STM32单片机编程调试常见问题(一) HardFault_Handler故障分析与解决

文章目录 一.概要二.什么是Hard fault三.Hard fault 产生的原因分析四.制作一个Hard fault程序并定位出问题原因1.查看堆栈指针SP的地址以及内容2.找到Return address地址3.查看汇编界面4.输入Return address地址&#xff0c;查找到问题代码 小结 一.概要 在嵌入式开发中&…

Hugging Face从命令行到桌面:Chat-macOS让AI互动更简单,关键还免费!

你是否曾经觉得,命令行操作虽然强大,但总是有些难以上手?或者,你是否希望和AI互动可以像日常使用macOS应用一样直观?那你一定要试试Chat-macOS,它让你从命令行走向桌面,体验更轻松的AI互动方式。 1. 什么是Chat-macOS? Chat-macOS是一个桌面应用程序,它能够将Hug…

pdf怎么转变成jpg图片?值得推荐的几种PDF转jpg方法

pdf怎么转变成jpg图片&#xff1f;jpg格式的图像在电子邮件、社交媒体等在线平台上分享非常方便&#xff0c;用户无需担心软件兼容性问题。将PDF内容转换为jpg后&#xff0c;能够有效保留原始文档的视觉布局&#xff0c;使信息更加生动易懂&#xff0c;适合用于演示和展示。同时…

六级翻译 高分笔记

第一节 句子的拆分与重组 核心原则&#xff1a;拆主干&#xff0c;补修饰 一、句子的拆分与重组 1.青藏铁路是世界最高最长的高原铁路。&#xff08;“的”字前面所有去掉&#xff0c;就是句子主干&#xff09; The Qinghai-Tibet Railway is the highest and longest plate…

工控主板在工业控制中扮演什么角色

工控主板在工业控制中扮演着至关重要的角色&#xff0c;它是工业控制系统的核心组件&#xff0c;负责连接、控制和管理各种工业设备&#xff0c;实现自动化生产和智能化管理。具体来说&#xff0c;工控主板在工业控制中的作用可以归纳为以下几个方面&#xff1a; 一、核心控制…

综合业务区的数字化创新与智能化蓝图

数字化智能管理的关键要素之一是综合业务区的电子标签系统&#xff0c;该系统在提高管理工作的效率、精确跟踪资源以及改善业务流程中扮演了至关重要的角色。以下内容将对这一综合业务区采用的智能电子标签系统进行深入剖析。 一、定义与功能 1.1定义 融合多功能于一体的智能…