当前位置:数据分析 > SM3

SM3

  • 发布:2023-10-06 08:40

算法过程

代码实现

国标

/**************************************************** **************************
文件名:SM3.c
版本:SM3_V1.1
日期:2016年9月18日
描述:根据给定消息计算哈希消息
功能列表:
www.sychzs.cn3_256 //调用SM3_init、SM3_process和SM3_done计算哈希值
www.sychzs.cn3_init //初始化SM3状态www.sychzs.cn3_process //压缩消息的前len/64块
www.sychzs.cn3_done //压缩剩余消息并输出哈希值
www.sychzs.cn3_compress //由SM3_process和SM3_done调用,压缩单个消息块
6.BiToW //被SM3_compress调用,根据Bi计算W
7.WToW1 //被SM3_compress调用,根据W计算W1
www.sychzs.cn //被SM3_compress调用,计算CF函数。
9.BigEndian //由SM3_compress和SM3_done调用。GM/T 0004-2012要求使用
大尾数。
//如果CPU使用little-endian,则必须调用BigEndian函数
改变
//小端格式转换为大端格式。
www.sychzs.cn3_SelfTest //通过比较哈希结果测试SM3计算是否正确
与标准结果
历史:
1. 日期:2016年9月18日
作者:毛莹莹、霍丽丽
修改:1)所有函数添加注释
2)添加SM3_SelfTest功能****************************************************** **********************/
#include“SM3.h”
/******************************************************** ******************************
功能:输入字符
描述:输出
****************************************************** ******************************/
void inputChar(无符号字符* Msg, int len)
{
int i,计数=0;
for (i = 0; i < len; i++)
{
printf("%02X\t", Msg[i]);
计数++;
如果(计数%8 == 0)
{
printf("\n");
}
}
}
/******************************************************** ******************************
功能:输入整数
描述:输出
****************************************************** ******************************/
void int(无符号 int* Msg, int len)
{
int i,计数 = 0;
for (i = 0; i < len; i++)
{
printf("%08X\t", Msg[i]);
计数++;
if (计数 % 8 == 0)
{
printf("\n");
}
}
}
/******************************************************** **************
功能:BiToW描述:根据Bi计算W【留言扩展】
来电:
调用者:SM3_compress
输入:Bi[16] //消息块
输出:W[64]
返回:空
其他:扩展消息组B[i],生成132个消息字W和W1,其中生成W
****************************************************** * ******************/
void BiToW(无符号整型 Bi[], 无符号整型 W[])
{
int i,计数=0;
无符号整型 tmp;
//消息扩展-A
//将消息组B[i]分为16个字W[i]
对于 (i = 0; i <= 15; i++)
{
W[i] = Bi[i];
}
//消息扩展-B
对于 (i = 16; i <= 67; i++)
{
tmp = W[i - 16]^ W[i - 9]^ SM3_rotl32(W[i - 3], 15);
W[i] = SM3_p1(tmp)^ (SM3_rotl32(W[i - 13], 7))^ W[i - 6];
}
int(W, 68);
}
/******************************************************** **********************
功能:WToW1
描述:从W计算W1
来电:
调用者:SM3_compress
输入:W[64]
输出:W1[64]
返回:空
其他:扩展消息组B[i],生成132个消息字W和W1。这里生成的是W1
****************************************************** *****************/void WToW1(无符号整型 W[], 无符号整型 W1[])
{
整数我;
//消息扩展-C,生成W1
对于 (i = 0; i <= 63; i++)
{
W1[i] = W[i] ^ W[i + 4];
}
int(W1, 64);
}
/******************************************************** ******************
功能:CF
说明:计算CF压缩函数并更新V【压缩函数】
来电:
调用者:SM3_compress
输入:W[64]
W1[64]
V[8]
输出:V[8]
返回:空
其他的:
****************************************************** ******************/
void CF(无符号整数 W[]、无符号整数 W1[]、无符号整数 V[])
{
无符号整型 SS1;
无符号整型 SS2;
无符号整型 TT1;
无符号整型 TT2;
无符号整型 A、B、C、D、E、F、G、H;
无符号整数 T = SM3_T1;
无符号整型 FF;
无符号整型 GG;
整数j;
printf("\n\n迭代压缩后的中间值:");
//ABCDEFGH=V0
A = V[0];
B = V[1];
C = V[2];
D = V[3];
E = V[4];
F = V[5];
G = V[6];
H = V[7];
printf("\nj\tA\t B\t C\t D\t E\t F\t G\t H\n");printf("\n\t%08X %08X %08X %08X %08X %08X %08X %08X\n", A, B, C, D, E, F, G, H);
对于 (j = 0; j <= 63; j++)
{
//SS1
如果(j==0)
{
T = SM3_T1;
}
否则如果 (j == 16)
{
T = SM3_rotl32(SM3_T2, 16);
}
别的
{
T = SM3_rotl32(T, 1);
}
SS1 = SM3_rotl32((SM3_rotl32(A, 12) + E + T), 7);
//SS2
SS2 = SS1 ^ SM3_rotl32(A, 12);
//TT1
如果(j <= 15)
{
FF = SM3_ff0(A,B,C);
}
别的
{
FF = SM3_ff1(A,B,C);
}
TT1 = FF + D + SS2 + *W1;
W1++;
//TT2
如果(j <= 15)
{
GG = SM3_gg0(E,F,G);
}
别的
{
GG = SM3_gg1(E,F,G);
}
TT2 = GG + H + SS1 + *W;
W++;
//D
D=C;
//C
C = SM3_rotl32(B, 9);
//B
B=A;
//A
A = TT1;
//H
H=G;
//G
G = SM3_rotl32(F, 19);
//F
F=E;
//E
E = SM3_p0(TT2);
printf("\n%d\t%08X %08X %08X %08X %08X %08X %08X %08X\n", j,A, B, C, D, E, F, G, H);
}
//更新V
V[0] = A^V[0];
V[1] = B^V[1];
V[2] = C^V[2];
V[3] = D^V[3];
V[4] = E^V[4];
V[5] = F^V[5];
V[6] = G^V[6];
V[7] = H^V[7];
}/******************************************************** ******************************
功能:大尾数
描述: 大端,高字节存储在低地址,低字节存储在高地址
来电:
调用者:SM3_compress、SM3_done
输入:src[bytelen]
字节伦
输出:des[bytelen]
返回:空
其他:src 和 des 可能暗示相同的地址
****************************************************** ******************************/
void BigEndian(无符号 char src[], 无符号 int bytelen, 无符号 char des[])
{
无符号字符 tmp = 0;
无符号整数 i = 0;
for (i = 0; i < bytelen / 4; i++)
{
tmp = des[4 * i];
des[4 * i] = src[4 * i + 3];
src[4 * i + 3] = tmp;
tmp = des[4 * i + 1];
des[4 * i + 1] = src[4 * i + 2];
des[4 * i + 2] = tmp;
}
}
/******************************************************** ******************************
函数:SM3_init
描述:启动SM3状态
来电:
调用者:SM3_256
输入:SM3_STATE *md
输出:SM3_STATE *md返回:空
其他的:
****************************************************** *********************************/
无效 SM3_init(SM3_STATE* md)
{
//md->state中保存IV,即V
md->curlen = md->length = 0;
md->状态[0] = SM3_IVA;
md->状态[1] = SM3_IVB;
md->状态[2] = SM3_IVC;
md->状态[3] = SM3_IVD;
md->状态[4] = SM3_IVE;
md->状态[5] = SM3_IVF;
md->状态[6] = SM3_IVG;
md->状态[7] = SM3_IVH;
}
/******************************************************** **************************************
功能:SM3_压缩
描述:压缩单个消息块
调用:BigEndian
双向
世界贸易组织1
CF
调用者:SM3_256
输入:SM3_STATE *md
输出:SM3_STATE *md
返回:空
其他的:
****************************************************** *********************************/
无效 SM3_compress(SM3_STATE* md)
{
//扩展消息组B[i],生成132个消息字W0,W1,...,W67,W'0,W'1,...,W'63
无符号整型 W[68]; //存储W
无符号整数 W1[64]; //存储W'
//字以big-endian格式存储,坐标为高位,右侧为低位。BigEndian(md->buf, 64, md->buf);
//消息扩展
printf("\n\n扩展消息:");
printf("\n\n********W0,W1,...,W67********:\n");
BiToW((无符号整数*)md->buf, W);
printf("\n\n********W'0,W'1,...,W'63********:\n");
WToW1(W, W1);
//压缩函数(W,W1,V[i])
CF(W, W1, md->状态);
}
/******************************************************** **************************************
函数:SM3_process
描述:压缩消息的前(len/64)块[迭代过程]
调用:SM3_compress
调用者:SM3_256
输入:SM3_STATE *md
unsigned char buf[len] //输入消息
int len ​​//消息的bytelen
输出:SM3_STATE *md
返回:空
其他的:
****************************************************** *********************************/
void SM3_process(SM3_STATE* md, unsigned char* buf, int len)
{
//将填充后的消息m'按照512位分组为B0,B1,...,Bn-1
int n = 1;//消息组数量
而 (len--)
{
/* 复制字节 */
md->buf[md->curlen] = *buf++;
md->curlen++;/* 64 字节已满吗?即是否是一组512位*/
if (md->curlen == 64)
{
printf("\n\n第%d个消息组:\n\n",n);
SM3_compress(md);
md->长度+= 512;
n++;
md->curlen = 0;
}
}
}
/******************************************************** **************************************
功能:SM3_done
描述:压缩SM3_process留下的剩余消息
调用:SM3_compress
调用者:SM3_256
输入:SM3_STATE *md
输出:unsigned char *hash
返回:空
其他的:
****************************************************** *********************************/
void SM3_done(SM3_STATE* md, unsigned char hash[])
{
int i,计数=1;
无符号字符 tmp = 0;
/* 增加消息的位长,使长度增加1个字节*/
md->长度 += md->curlen << 3;
/* 附加“1”位 首先将“1”位添加到消息末尾 */
md->buf[md->curlen] = 0x80;
md->curlen++;
/* 如果当前长度超​​过 56 字节,则追加零直到
达到64字节,压缩当前块,创建一个新块通过附加零和长度来块,然后压缩它
如果当前长度超​​过56字节(512位),则加0直到64字节,然后迭代压缩
*/
if (md->curlen > 56)
{
for (; md->curlen < 64;)
{
md->buf[md->curlen] = 0;
md->curlen++;
}
//64字节作为一组进行迭代压缩
SM3_compress(md);
//将长度设置为0并再次创建一个新块
md->curlen = 0;
}
/* 如果长度小于 56 字节,则最多填充 56 字节的零
如果长度小于56字节,则填充0到56字节
*/
for (; md->curlen < 56;)
{
md->buf[md->curlen] = 0;
md->curlen++;
}
/* 由于所有消息都低于 2^32 位,我们将最高位标记为零
由于所有消息都在 2^32 位以下,因此最高位标记为 0
*/
对于 (i = 56; i < 60; i++)
{
md->buf[i] = 0;
}
/*append length添加一个64位的字符串,它是长度l的二进制表示*/
md->buf[63] = md->长度&0xff;
md->buf[62] = (md->长度>> 8) & 0xff;
md->buf[61] = (md->长度 >> 16) & 0xff;
md->buf[60] = (md->长度 >> 24) & 0xff;
printf("\n************填写的消息************:\n");
inputChar(md->buf, 64);
SM3_compress(md);
/* 复制输出 */
memcpy(哈希,md->状态,SM3_len / 8);
//如果CPU使用little-endian,则必须调用BigEndian函数BigEndian(哈希, SM3_len / 8, 哈希);
}
/******************************************************** ******************************
功能:SM3_256
描述:根据给定消息计算哈希值
调用:SM3_init
SM3_进程
SM3_完成
呼叫者:
输入:unsigned char buf[len] //输入消息
int len //消息的bytelen
输出:unsigned char hash[32]
返回:空
其他的:
****************************************************** ******************************/
void SM3_256(无符号字符 buf[], int len, 无符号字符哈希[])
{
SM3_STATE md;
SM3_init(&md);
SM3_process(&md, buf, len);
SM3_done(&md, 哈希);
}
/******************************************************** ******************************
功能:SM3_自检
说明:通过比较测试SM3计算是否正确
哈希结果与标准结果
呼叫:SM3_256
呼叫者:
输入:空输出:空
Return: 0 //SM3操作正确
1 //sm3操作错误
其他的:
****************************************************** *********************************/
无效 SM3_SelfTest()
{
无符号整型 i = 0,a = 1,b = 1;
整数选择;
printf("请选择输入示例:1.示例1\t\t2.示例2\n");
scanf("%d",&选择);
如果(选择==1)
{
//示例1
unsigned char Msg1[3] = { 0x61,0x62,0x63 };//ASCII码
int MsgLen1 = 3;
无符号字符 MsgHash1[32] = { 0 }; //生成的Hash值
printf("\n*****输入字符串消息************:\n");
inputChar(Msg1, MsgLen1);
/*
无符号字符 StdHash1[32] = { 0x66,0xC7,0xF0,0xF4,0x62,0xEE,0xED,0xD9,0xD1,0xF2,0xD4,0x6B,0xDC,0x10,0xE4,0xE2,
0x41,0x67,0xC4,0x87,0x5C,0xF2,0xF7,0xA2,0x29,0x7D,0xA0,0x2B,0x8F,0x4B,0xA8,0xE0 };//计算出的Hash值
*/
SM3_256(Msg1, MsgLen1, MsgHash1);
printf("\n*****输出哈希值************:\n");
inputChar(MsgHash1, 32);
}
否则如果(选择 == 2)
{
//示例2无符号字符Msg2[64] = { 0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64 };// ASCII码
int MsgLen2 = 64;
unsigned char MsgHash2[32] = { 0 };//生成的Hash值
printf("\n*******输入的字符串消息*******:\n");
inputChar(Msg2, MsgLen2);
/*
unsigned char StdHash2[32] = { 0xde,0xbe,0x9f,0xf9,0x22,0x75,0xb8,0xa1,0x38,0x60,0x48,0x89,0xc1,0x8e,0x5a,0x4d,
0x6f,0xdb,0x70,0xe5,0x38,0x7e,0x57,0x65,0x29,0x3d,0xcb,0xa3,0x9c,0x0c,0x57,0x32 };//已经计算好的Hash值
*/
SM3_256(Msg2, MsgLen2, MsgHash2);
printf("\n*******输出杂凑值*******:\n");
inputChar(MsgHash2, 32);
}
else
printf("输入错误,请重新输入!\n");
//比较是否相同
/*
a = memcmp(MsgHash1, StdHash1, SM3_len / 8);
b = memcmp(MsgHash2, StdHash2, SM3_len / 8);
if ((a == 0) && (b == 0))
{
return 0;
}
else
{
return 1;
}
*/
}
int main()
{
printf("*********************************************************\n");
printf("*\t\t\tSM3密码杂凑算法\t\t\t*\n");
printf("*********************************************************\n\n");
SM3_SelfTest();
printf("\n");
system("pause");
return 0;
}

openSSL中提取

参考:SM3算法 C语言 (从OpenSSL库中分离算法:六)

 

#include 
#include "sm3/sm3.h"
int main()
{
SM3_CTX SMC;
ossl_sm3_init(&SMC);
const unsigned char Data[1024] = "Hello World";
unsigned char md[SM3_DIGEST_LENGTH] = { 0 };
printf("input message:%s\n",Data);
ossl_sm3_update(&SMC, Data, strlen((const char *) Data));
ossl_sm3_final(md, &SMC);
printf("output hash value:");
for (int i = 0; i < SM3_DIGEST_LENGTH; i++) {
printf("%02x ", *(md + i));
}
}

注:代码见github

参考

1、国标-SM3

2、商用密码检测中心-源码下载

3、密码学-基础理论与应用(李子臣著)

相关文章