国密即国家密码局认定的国产密码算法.主要有 SM1,SM2,SM3,SM4.密钥长度和分组长度均为 128 位.
SM3是我国采用的的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。
SM3密码杂凑算法采用Merkle-Damgard结构,消息分组长度为512b,摘要长度256b。压缩函数状态256b,共64步操作步骤。
在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。
密码散列函数又称为加密散列函数,是散列函数的一种,被认为是一种单向函数,很难由刺中函数输出的结果反推出输入的数据。此类散列函数的输入数据,通常被称为消息(message)。而它的输出结果,通常被称为消息摘要(message digest)或摘要(digest)。
散列函数在密码学中具有重要的地位,它们通常被认为需要满足三个基本特性:
对于所有预设输出,从计算角度应无法找到任何符合输入哈希的输出。例如,给定y,使得很难找到满足h(x) = y的x。这样的散列函数我们称之为原像稳定。
从计算角度无法找到任何与特定输入值有着相同输出的二次输入值。例如,给定x,使得很难找到满足h(x) = h(x′)的次原像x′ ≠ x。
很难找到满足h(x)=h(x’)的二元组(x,x’)。
满足以上三个特性的散列函数可以认为是安全的散列函数,按照美国国家标准与技术研究院(NIST)的标准,MD5已经是不安全的散列函数了,不推荐使用SHA-1,推荐使用SHA-2与SHA-3。
SM3密码摘要算法适用于商用密码应用中的数字签名和验证,是在SHA-256基础上改进并实现的一种算法。SM3算法采用Merkle-Damgard结构,消息分组长度为512位,摘要值长度为256位。
SM3算法的压缩函数与SHA-256的压缩函数具有相似的结构,但是SM3算法的设计更加复杂,比如压缩函数的每一轮都使用2个消息字。
至今为止,SM3算法的安全性相对而言比较高。
SM3散列函数会对输入消息做填充,迭代压缩,输出256比特的杂凑值这三项操作,而迭代压缩中又分:迭代过程、消息扩展、压缩函数。
假设消息M的长度为l比特,则首先将比特“1”添加到消息的末尾,在添加k个“0”,k是满足l+1+k===448(mod512)的最小非负整数。然后在添加一个64位比特串,该比特串是长度l的二进制表示。填充后的消息M1的比特长度为512的倍数。
将填充后的消息M1按512比特进行分组。
M1 = C^0 C^1...k^N-1
其中n=(l+k+65)/512
对M1按以下方式迭代:
FOR I=0 TO N-1
V^I+1 = CF(V^I,B^I)
ENDFOR
其中CF是压缩函数,V^0为256比特初始值IV,B^i为填充后的消息分组,得带压缩的结果为V^n
将消息分组 B^i按以下方法扩展生成132个消息字用于压缩函数CF;
令A,B,C,D,E,F,G,H为字寄存器,SS1,SS2,TT1,TT2为中间变量,压缩函数V^i+1=CF(V^I,B^I),0<=i<=n-1
ABCDEFGH <- V^n
输出256比特的杂凑值y=ABCDEFGH。
具体的代码实现需要弄清楚加密原理,下面是使用JAVA实现的SM3加密代码:
首先是填充,迭代与消息扩展。
private static byte[] CF(byte[] vi, byte[] bi) throws IOException {
int a, b, c, d, e, f, g, h;
a = toInteger(vi, 0);
b = toInteger(vi, 1);
c = toInteger(vi, 2);
d = toInteger(vi, 3);
e = toInteger(vi, 4);
f = toInteger(vi, 5);
g = toInteger(vi, 6);
h = toInteger(vi, 7);
int[] w = new int[68];
int[] w1 = new int[64];
for (int i = 0; i < 16; i++) {
w[i] = toInteger(bi, i);
}
for (int j = 16; j < 68; j++) {
w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))
^ Integer.rotateLeft(w[j - 13], 7) ^ w[j - 6];
}
for (int j = 0; j < 64; j++) {
w1[j] = w[j] ^ w[j + 4];
}
int ss1, ss2, tt1, tt2;
for (int j = 0; j < 64; j++) {
ss1 = Integer.rotateLeft(Integer.rotateLeft(a, 12) + e + Integer.rotateLeft(TJT(j), j), 7);
ss2 = ss1 ^ Integer.rotateLeft(a, 12);
tt1 = FJF(a, b, c, j) + d + ss2 + w1[j];
tt2 = GJG(e, f, g, j) + h + ss1 + w[j];
d = c;
c = Integer.rotateLeft(b, 9);
b = a;
a = tt1;
h = g;
g = Integer.rotateLeft(f, 19);
f = e;
e = P0(tt2);
}
byte[] v = toByteArray(a, b, c, d, e, f, g, h);
for (int i = 0; i < v.length; i++) {
v[i] = (byte) (v[i] ^ vi[i]);
}
return v;
}
然后是压缩函数。
private static int TJT(int j) {
if (j >= 0 && j <= 15) {
return Tj11;
} else if (j >= 16 && j <= 63) {
return Tj61;
} else {
throw new RuntimeException("DI");
}
}
private static Integer FJF(Integer x, Integer y, Integer z, int j) {
if (j >= 0 && j <= 15) {
return x ^ y ^ z;
} else if (j >= 16 && j <= 63) {
return (x & y)|(x & z)|(y & z);
} else {
throw new RuntimeException("DI");
}
}
private static Integer GJG(Integer x, Integer y, Integer z, int j) {
if (j >= 0 && j <= 15) {
return x ^ y ^ z;
} else if (j >= 16 && j <= 63) {
return (x & y)|(~x & z);
} else {
throw new RuntimeException("DI");
}
}
最后将压缩完的杂凑值输出,结合图形化显示效果如下:
在越来越多国际通用散列算法被攻击、破解的今日,我国自研的SM3散列函数使用更复杂的压缩函数,因此具有更高的安全性,为金融、政企类网站保驾护航,守护信息安全。
本文作者 r0fus0d、RyuZU
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。