/**************************************************** ************************** 文件名: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; }
参考:SM3算法 C语言 (从OpenSSL库中分离算法:六)
注:代码见github 1、国标-SM3 2、商用密码检测中心-源码下载 3、密码学-基础理论与应用(李子臣著)openSSL中提取
#include
参考