背景介绍:
项目应某客户要求,需要对密码等安全属性要求高的字段进行加密保护与传输,并且必须使用国密(SM2, SM3, SM4)加密算法,项目是C++语言开发,需要与java前端进行调试,本人以前也没有接触过加密算法,因此查询了很多资料,走了很多弯路,现在将自己整理的关于SM2算法一些东西发出来,希望可以对有需要的小伙伴有所帮助。
场景介绍:
假设,给了你一个hex编码的公钥,然后给了一个待加密字段,如何加密,或者说给了一个hex编码的私钥,给了一个hex编码的待解密字段,如何解密?我的文章就围绕这个给您解答。
特别感谢
感谢两位博主的文章及其开源项目,通过他们的源码学到了很多东西,以下为链接:
https://github.com/greendow/SM2-encrypt-and-decrypt
https://github.com/NEWPLAN/SMx
前置介绍
文档
- 文档请参考官方文档,但是官方示例为C1C2C3加密模式,
- 需要使用到openssl,所以我windows安装了openssl来进行调试,安装版本为openssl-1.1.1b,安装教程可以参考:
https://blog.csdn.net/weixin_41642793/article/details/90407107
公钥及私钥介绍:
- 公钥:公钥是一个65字节长的字符数组,用于加密使用
- 组成:04 || X || Y,X和Y是公钥的坐标点,长度各为32位,这个需要理解
- 私钥:私钥是一个由32字节长度组成的字节数组,用于解密使用
加密模式
- 本次采用C1C3C2加密模式,下边是一个需要用到的宏定义:
#define BUFFER_APPEND_STRING(buffer1, pos1, length1, x) \
memcpy(&buffer1[pos1], x, length1); \
pos1 = pos1 + length1
流程讲解
加密流程
- 收到一个hex编码的公钥
040471008F95FFD0E1F8AD1CC886E09402F45CC8A935DAE145B88B3768C80BF6E18879AAE458FEFBBB7114F6D9F11192860359FA50B403293F00592A6061B59F8F
- 收到一个待加密字段
I have a dream!
- 经过加密获取到C1,C2, C3的值
- 接下来调用这个函数,便可以获取到加密后的字段,但是这里是内存字节,通常我们将它转成hex编码的字符串:
void setMessage(const unsigned char* c1,
const unsigned char* c2,
const unsigned char* c3,
const unsigned char* messagg,
const unsigned int msgByteLen)
{
int pos1 = 0;
BUFFER_APPEND_STRING(messagg, pos1, 1 + 64
, c1);
BUFFER_APPEND_STRING(messagg, pos1, 32
, c3);
BUFFER_APPEND_STRING(messagg, pos1, msgByteLen
, c2);
DEFINE_SHOW_STRING(messagg, pos1);
}
解密过程:
- 输入hex编码私钥:
3A2C8E1BB7B922FC7CB8E32FE7EFB6C1F3C0BF3ABAFE5560552BF67DA55BFD4B
- 输入待解密字段:
0404EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF096AEA0772D8FE093BFB72FD6C5AF50007A052EA7CA6F1FF2D2C258B84647BBDB821D028B7A3E21D17CCFF4A34ECD19
- 首先进行hexdecode,然后通过下边的这个函数我们便可以获取到C1,C2, C3的值
void getMessage(unsigned char* c1,
unsigned char* c2,
unsigned char* c3,
const unsigned char* messagg,
const unsigned int msgByteLen)
{
int pos1 = 0;
int pos2 = 0;
BUFFER_APPEND_STRING(c1, pos1, 1 + 64
, &messagg[pos2]);
DEFINE_SHOW_STRING(c1, pos1);
pos2 = pos2 + pos1;
pos1 = 0;
BUFFER_APPEND_STRING(c3, pos1, 32
, &messagg[pos2]);
DEFINE_SHOW_STRING(c3, 32);
pos2 = pos2 + pos1;
pos1 = 0;
BUFFER_APPEND_STRING(c2, pos1, (msgByteLen - pos2)
, &messagg[pos2]);
DEFINE_SHOW_STRING(c2, msgByteLen - pos2);
}
- 然后我们调用解密接口,即可获取到解密后的字段。