SM3是国产哈希算法,在商用密码体系中,主要用于数字签名及验证、消息认证码生成及验证、随机数生成等。对于用户需要加密的数据在加密后会生成一个固定长度(32字节)的哈希值。SM3算法是公开的。实现原理如下图所示:
C代码展示:
完整代码见github:https://github.com/CMwshuai/Algorithm.git
1、初始值IV
static const unsigned int IV[8] =
{
0x7380166F, 0x4914B2B9,
0x172442D7, 0xDA8A0600,
0xA96F30BC, 0x163138AA,
0xE38DEE4D, 0xB0FB0E4E,
};
2、常量初始化T
static void _init_T()
{
int i = 0;
for (; i < 16; i++)
T[i] = 0x79CC4519;
for (; i < 64; i++)
T[i] = 0x7A879D8A;
}
3、 布尔函数_FF,_GG
static unsigned int _FF(
const unsigned int X,
const unsigned int Y,
const unsigned int Z,
const unsigned int j)
{
if (0 <= j && j < 16)
return (X ^ Y ^ Z);
else if (16 <= j && j < 64)
return ((X & Y) | (X & Z) | (Y & Z));
return 0;
}
static unsigned int _GG(
const unsigned int X,
const unsigned int Y,
const unsigned int Z,
const unsigned int j)
{
if (0 <= j && j < 16)
return (X ^ Y ^ Z);
else if (16 <= j && j < 64)
return ((X & Y) | ((~X) & Z));
return 0;
}
4、置换函数_P0,_P1
static unsigned int _P0(const unsigned int X)
{
return (X ^ (_rotate_left_move(X, 9)) ^ (_rotate_left_move(X, 17)));
}
static unsigned int _P1(const unsigned int X)
{
return (X ^ (_rotate_left_move(X, 15)) ^ (_rotate_left_move(X, 23)));
}
5、消息填充
unsigned int nGroupNum = (nSrcLen + 1 + 8 + 64) / 64;
unsigned char *ucpMsgBuf = (unsigned char*)malloc(nGroupNum * 64);
memset(ucpMsgBuf, 0, nGroupNum * 64);
memcpy(ucpMsgBuf, ucpSrcData, nSrcLen);
ucpMsgBuf[nSrcLen] = 0x80;
int i = 0;
for (i = 0; i < 8; i++)
{
ucpMsgBuf[nGroupNum * 64 - i - 1] = ((unsigned long long)(nSrcLen * 8) >> (i * 8)) & 0xFF;
}
6、迭代压缩
static unsigned int _CF(unsigned char* ucpSrcMsg, unsigned int nHash[8])
{
unsigned int W68[68] = { 0 };
unsigned int W64[64] = { 0 };
//message extension
int j = 0;
for (j = 0; j < 16; j++)
{
W68[j] = ((unsigned int)ucpSrcMsg[j * 4 + 0] << 24) & 0xFF000000
| ((unsigned int)ucpSrcMsg[j * 4 + 1] << 16) & 0x00FF0000
| ((unsigned int)ucpSrcMsg[j * 4 + 2] << 8) & 0x0000FF00
| ((unsigned int)ucpSrcMsg[j * 4 + 3] << 0) & 0x000000FF;
}
for (j = 16; j < 68; j++)
{
W68[j] = _P1(W68[j - 16] ^ W68[j - 9] ^ (_rotate_left_move(W68[j - 3], 15))) ^ (_rotate_left_move(W68[j - 13], 7)) ^ W68[j - 6];
}
for (j = 0; j < 64; j++)
{
W64[j] = W68[j] ^ W68[j + 4];
}
//iterative process
unsigned int A_G[8] = { 0 };
for (j = 0; j < 8; j++)
{
A_G[j] = nHash[j];
}
//tempporary variable
unsigned int SS1 = 0, SS2 = 0, TT1 = 0, TT2 = 0;
for (j = 0; j < 64; j++)
{
SS1 = _rotate_left_move((_rotate_left_move(A_G[A], 12) + A_G[E] + _rotate_left_move(T[j], j % 32)), 7);
SS2 = SS1 ^ (_rotate_left_move(A_G[A], 12));
TT1 = _FF(A_G[A], A_G[B], A_G[C], j) + A_G[D] + SS2 + W64[j];
TT2 = _GG(A_G[E], A_G[F], A_G[G], j) + A_G[H] + SS1 + W68[j];
A_G[D] = A_G[C];
A_G[C] = _rotate_left_move(A_G[B], 9);
A_G[B] = A_G[A];
A_G[A] = TT1;
A_G[H] = A_G[G];
A_G[G] = _rotate_left_move(A_G[F], 19);
A_G[F] = A_G[E];
A_G[E] = _P0(TT2);
}
for (j = 0; j < 8; j++)
{
nHash[j] = A_G[j] ^ nHash[j];
}
return 0;
}