【摘要】
本文主要讲解“国密加密算法”SM系列的Java实现方法,不涉及具体的算法剖析,在网络上找到的java实现方法比较少,切在跨语言加密解密上会存在一些问题,所以整理此文志之。
源码下载地址http://download.youkuaiyun.com/detail/ererfei/9474502需要C#实现SM系列算法源码的可以评论留邮箱地址,看到后发送
1.SM2 & SM3
由于SM2算法中需要使用SM3摘要算法,所以把他们放在一起
项目目录结构如下:
首先要下载一个jar包——bcprov-jdk.jar,可以到maven库中下载最新版http://central.maven.org/maven2/org/bouncycastle/并将该jar包引入项目的classpath。实现代码如下(每个工具类都有Main可以运行测试):
a.SM2主类
【SM2.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
package
com.mlq.sm;
import
java.math.BigInteger;
import
java.security.SecureRandom;
import
org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import
org.bouncycastle.crypto.params.ECDomainParameters;
import
org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import
org.bouncycastle.math.ec.ECCurve;
import
org.bouncycastle.math.ec.ECFieldElement;
import
org.bouncycastle.math.ec.ECPoint;
import
org.bouncycastle.math.ec.ECFieldElement.Fp;
public
class
SM2
{
//测试参数
// public static final String[] ecc_param = {
// "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
// "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
// "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
// "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
// "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
// "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
// };
//正式参数
public
static
String[] ecc_param = {
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
,
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"
,
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"
,
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
,
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
,
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
};
public
static
SM2 Instance()
{
return
new
SM2();
}
public
final
BigInteger ecc_p;
public
final
BigInteger ecc_a;
public
final
BigInteger ecc_b;
public
final
BigInteger ecc_n;
public
final
BigInteger ecc_gx;
public
final
BigInteger ecc_gy;
public
final
ECCurve ecc_curve;
public
final
ECPoint ecc_point_g;
public
final
ECDomainParameters ecc_bc_spec;
public
final
ECKeyPairGenerator ecc_key_pair_generator;
public
final
ECFieldElement ecc_gx_fieldelement;
public
final
ECFieldElement ecc_gy_fieldelement;
public
SM2()
{
this
.ecc_p =
new
BigInteger(ecc_param[
0
],
16
);
this
.ecc_a =
new
BigInteger(ecc_param[
1
],
16
);
this
.ecc_b =
new
BigInteger(ecc_param[
2
],
16
);
this
.ecc_n =
new
BigInteger(ecc_param[
3
],
16
);
this
.ecc_gx =
new
BigInteger(ecc_param[
4
],
16
);
this
.ecc_gy =
new
BigInteger(ecc_param[
5
],
16
);
this
.ecc_gx_fieldelement =
new
Fp(
this
.ecc_p,
this
.ecc_gx);
this
.ecc_gy_fieldelement =
new
Fp(
this
.ecc_p,
this
.ecc_gy);
this
.ecc_curve =
new
ECCurve.Fp(
this
.ecc_p,
this
.ecc_a,
this
.ecc_b);
this
.ecc_point_g =
new
ECPoint.Fp(
this
.ecc_curve,
this
.ecc_gx_fieldelement,
this
.ecc_gy_fieldelement);
this
.ecc_bc_spec =
new
ECDomainParameters(
this
.ecc_curve,
this
.ecc_point_g,
this
.ecc_n);
ECKeyGenerationParameters ecc_ecgenparam;
ecc_ecgenparam =
new
ECKeyGenerationParameters(
this
.ecc_bc_spec,
new
SecureRandom());
this
.ecc_key_pair_generator =
new
ECKeyPairGenerator();
this
.ecc_key_pair_generator.init(ecc_ecgenparam);
}
}
|
b.SM2工具类
【SM2Utils.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package
com.mlq.sm;
import
java.io.IOException;
import
java.math.BigInteger;
import
org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import
org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import
org.bouncycastle.crypto.params.ECPublicKeyParameters;
import
org.bouncycastle.math.ec.ECPoint;
public
class
SM2Utils
{
//生成随机秘钥对
public
static
void
generateKeyPair(){
SM2 sm2 = SM2.Instance();
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
BigInteger privateKey = ecpriv.getD();
ECPoint publicKey = ecpub.getQ();
System.out.println(
"公钥: "
+ Util.byteToHex(publicKey.getEncoded()));
System.out.println(
"私钥: "
+ Util.byteToHex(privateKey.toByteArray()));
}
//数据加密
public
static
String encrypt(
byte
[] publicKey,
byte
[] data)
throws
IOException
{
if
(publicKey ==
null
|| publicKey.length ==
0
)
{
return
null
;
}
if
(data ==
null
|| data.length ==
0
)
{
return
null
;
}
byte
[] source =
new
byte
[data.length];
System.arraycopy(data,
0
, source,
0
, data.length);
Cipher cipher =
new
Cipher();
SM2 sm2 = SM2.Instance();
ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
ECPoint c1 = cipher.Init_enc(sm2, userKey);
cipher.Encrypt(source);
byte
[] c3 =
new
byte
[
32
];
cipher.Dofinal(c3);
// System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
// System.out.println("C2 " + Util.byteToHex(source));
// System.out.println("C3 " + Util.byteToHex(c3));
//C1 C2 C3拼装成加密字串
return
Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);
}
//数据解密
public
static
byte
[] decrypt(
byte
[] privateKey,
byte
[] encryptedData)
throws
IOException
{
if
(privateKey ==
null
|| privateKey.length ==
0
)
{
return
null
;
}
if
(encryptedData ==
null
|| encryptedData.length ==
0
)
{
return
null
;
}
//加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
String data = Util.byteToHex(encryptedData);
/***分解加密字串
* (C1 = C1标志位2位 + C1实体部分128位 = 130)
* (C3 = C3实体部分64位 = 64)
* (C2 = encryptedData.length * 2 - C1长度 - C2长度)
*/
byte
[] c1Bytes = Util.hexToByte(data.substring(
0
,
130
));
int
c2Len = encryptedData.length -
97
;
byte
[] c2 = Util.hexToByte(data.substring(
130
,
130
+
2
* c2Len));
byte
[] c3 = Util.hexToByte(data.substring(
130
+
2
* c2Len,
194
+
2
* c2Len));
SM2 sm2 = SM2.Instance();
BigInteger userD =
new
BigInteger(
1
, privateKey);
//通过C1实体字节来生成ECPoint
ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
Cipher cipher =
new
Cipher();
cipher.Init_dec(userD, c1);
cipher.Decrypt(c2);
cipher.Dofinal(c3);
//返回解密结果
return
c2;
}
public
static
void
main(String[] args)
throws
Exception
{
//生成密钥对
generateKeyPair();
String plainText =
"ererfeiisgod"
;
byte
[] sourceData = plainText.getBytes();
//下面的秘钥可以使用generateKeyPair()生成的秘钥内容
// 国密规范正式私钥
String prik =
"3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94"
;
// 国密规范正式公钥
String pubk =
"04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A"
;
System.out.println(
"加密: "
);
String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);
System.out.println(cipherText);
System.out.println(
"解密: "
);
plainText =
new
String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));
System.out.println(plainText);
}
}
|
c.SM3主类
【SM3.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
package
com.mlq.sm;
public
class
SM3
{
public
static
final
byte
[] iv = {
0x73
, (
byte
)
0x80
,
0x16
,
0x6f
,
0x49
,
0x14
, (
byte
)
0xb2
, (
byte
)
0xb9
,
0x17
,
0x24
,
0x42
, (
byte
)
0xd7
,
(
byte
)
0xda
, (
byte
)
0x8a
,
0x06
,
0x00
, (
byte
)
0xa9
,
0x6f
,
0x30
,
(
byte
)
0xbc
, (
byte
)
0x16
,
0x31
,
0x38
, (
byte
)
0xaa
, (
byte
)
0xe3
,
(
byte
)
0x8d
, (
byte
)
0xee
,
0x4d
, (
byte
)
0xb0
, (
byte
)
0xfb
,
0x0e
,
0x4e
};
public
static
int
[] Tj =
new
int
[
64
];
static
{
for
(
int
i =
0
; i <
16
; i++)
{
Tj[i] =
0x79cc4519
;
}
for
(
int
i =
16
; i <
64
; i++)
{
Tj[i] =
0x7a879d8a
;
}
}
public
static
byte
[] CF(
byte
[] V,
byte
[] B)
{
int
[] v, b;
v = convert(V);
b = convert(B);
return
convert(CF(v, b));
}
private
static
int
[] convert(
byte
[] arr)
{
int
[] out =
new
int
[arr.length /
4
];
byte
[] tmp =
new
byte
[
4
];
for
(
int
i =
0
; i < arr.length; i +=
4
)
{
System.arraycopy(arr, i, tmp,
0
,
4
);
out[i /
4
] = bigEndianByteToInt(tmp);
}
return
out;
}
private
static
byte
[] convert(
int
[] arr)
{
byte
[] out =
new
byte
[arr.length *
4
];
byte
[] tmp =
null
;
for
(
int
i =
0
; i < arr.length; i++)
{
tmp = bigEndianIntToByte(arr[i]);
System.arraycopy(tmp,
0
, out, i *
4
,
4
);
}
return
out;
}
public
static
int
[] CF(
int
[] V,
int
[] B)
{
int
a, b, c, d, e, f, g, h;
int
ss1, ss2, tt1, tt2;
a = V[
0
];
b = V[
1
];
c = V[
2
];
d = V[
3
];
e = V[
4
];
f = V[
5
];
g = V[
6
];
h = V[
7
];
int
[][] arr = expand(B);
int
[] w = arr[
0
];
int
[] w1 = arr[
1
];
for
(
int
j =
0
; j <
64
; j++)
{
ss1 = (bitCycleLeft(a,
12
) + e + bitCycleLeft(Tj[j], j));
ss1 = bitCycleLeft(ss1,
7
);
ss2 = ss1 ^ bitCycleLeft(a,
12
);
tt1 = FFj(a, b, c, j) + d + ss2 + w1[j];
tt2 = GGj(e, f, g, j) + h + ss1 + w[j];
d = c;
c = bitCycleLeft(b,
9
);
b = a;
a = tt1;
h = g;
g = bitCycleLeft(f,
19
);
f = e;
e = P0(tt2);
/*System.out.print(j+" ");
System.out.print(Integer.toHexString(a)+" ");
System.out.print(Integer.toHexString(b)+" ");
System.out.print(Integer.toHexString(c)+" ");
System.out.print(Integer.toHexString(d)+" ");
System.out.print(Integer.toHexString(e)+" ");
System.out.print(Integer.toHexString(f)+" ");
System.out.print(Integer.toHexString(g)+" ");
System.out.print(Integer.toHexString(h)+" ");
System.out.println("");*/
}
// System.out.println("");
int
[] out =
new
int
[
8
];
out[
0
] = a ^ V[
0
];
out[
1
] = b ^ V[
1
];
out[
2
] = c ^ V[
2
];
out[
3
] = d ^ V[
3
];
out[
4
] = e ^ V[
4
];
out[
5
] = f ^ V[
5
];
out[
6
] = g ^ V[
6
];
out[
7
] = h ^ V[
7
];
return
out;
}
private
static
int
[][] expand(
int
[] B)
{
int
W[] =
new
int
[
68
];
int
W1[] =
new
int
[
64
];
for
(
int
i =
0
; i < B.length; i++)
{
W[i] = B[i];
}
for
(
int
i =
16
; i <
68
; i++)
{
W[i] = P1(W[i -
16
] ^ W[i -
9
] ^ bitCycleLeft(W[i -
3
],
15
))
^ bitCycleLeft(W[i -
13
],
7
) ^ W[i -
6
];
}
for
(
int
i =
0
; i <
64
; i++)
{
W1[i] = W[i] ^ W[i +
4
];
}
int
arr[][] =
new
int
[][] { W, W1 };
return
arr;
}
private
static
byte
[] bigEndianIntToByte(
int
num)
{
return
back(Util.intToBytes(num));
}
private
static
int
bigEndianByteToInt(
byte
[] bytes)
{
return
Util.byteToInt(back(bytes));
}
private
static
int
FFj(
int
X,
int
Y,
int
Z,
int
j)
{
if
(j >=
0
&& j <=
15
)
{
return
FF1j(X, Y, Z);
}
else
{
return
FF2j(X, Y, Z);
}
}
private
static
int
GGj(
int
X,
int
Y,
int
Z,
int
j)
{
if
(j >=
0
&& j <=
15
)
{
return
GG1j(X, Y, Z);
}
else
{
return
GG2j(X, Y, Z);
}
}
// 逻辑位运算函数
private
static
int
FF1j(
int
X,
int
Y,
int
Z)
{
int
tmp = X ^ Y ^ Z;
return
tmp;
}
private
static
int
FF2j(
int
X,
int
Y,
int
Z)
{
int
tmp = ((X & Y) | (X & Z) | (Y & Z));
return
tmp;
}
private
static
int
GG1j(
int
X,
int
Y,
int
Z)
{
int
tmp = X ^ Y ^ Z;
return
tmp;
}
private
static
int
GG2j(
int
X,
int
Y,
int
Z)
{
int
tmp = (X & Y) | (~X & Z);
return
tmp;
}
private
static
int
P0(
int
X)
{
int
y = rotateLeft(X,
9
);
y = bitCycleLeft(X,
9
);
int
z = rotateLeft(X,
17
);
z = bitCycleLeft(X,
17
);
int
t = X ^ y ^ z;
return
t;
}
private
static
int
P1(
int
X)
{
int
t = X ^ bitCycleLeft(X,
15
) ^ bitCycleLeft(X,
23
);
return
t;
}
/**
* 对最后一个分组字节数据padding
*
* @param in
* @param bLen
* 分组个数
* @return
*/
public
static
byte
[] padding(
byte
[] in,
int
bLen)
{
int
k =
448
- (
8
* in.length +
1
) %
512
;
if
(k <
0
)
{
k =
960
- (
8
* in.length +
1
) %
512
;
}
k +=
1
;
byte
[] padd =
new
byte
[k /
8
];
padd[
0
] = (
byte
)
0x80
;
long
n = in.length *
8
+ bLen *
512
;
byte
[] out =
new
byte
[in.length + k /
8
+
64
/
8
];
int
pos =
0
;
System.arraycopy(in,
0
, out,
0
, in.length);
pos += in.length;
System.arraycopy(padd,
0
, out, pos, padd.length);
pos += padd.length;
byte
[] tmp = back(Util.longToBytes(n));
System.arraycopy(tmp,
0
, out, pos, tmp.length);
return
out;
}
/**
* 字节数组逆序
*
* @param in
* @return
*/
private
static
byte
[] back(
byte
[] in)
{
byte
[] out =
new
byte
[in.length];
for
(
int
i =
0
; i < out.length; i++)
{
out[i] = in[out.length - i -
1
];
}
return
out;
}
public
static
int
rotateLeft(
int
x,
int
n)
{
return
(x << n) | (x >> (
32
- n));
}
private
static
int
bitCycleLeft(
int
n,
int
bitLen)
{
bitLen %=
32
;
byte
[] tmp = bigEndianIntToByte(n);
int
byteLen = bitLen /
8
;
int
len = bitLen %
8
;
if
(byteLen >
0
)
{
tmp = byteCycleLeft(tmp, byteLen);
}
if
(len >
0
)
{
tmp = bitSmall8CycleLeft(tmp, len);
}
return
bigEndianByteToInt(tmp);
}
private
static
byte
[] bitSmall8CycleLeft(
byte
[] in,
int
len)
{
byte
[] tmp =
new
byte
[in.length];
int
t1, t2, t3;
for
(
int
i =
0
; i < tmp.length; i++)
{
t1 = (
byte
) ((in[i] &
0x000000ff
) << len);
t2 = (
byte
) ((in[(i +
1
) % tmp.length] &
0x000000ff
) >> (
8
- len));
t3 = (
byte
) (t1 | t2);
tmp[i] = (
byte
) t3;
}
return
tmp;
}
private
static
byte
[] byteCycleLeft(
byte
[] in,
int
byteLen)
{
byte
[] tmp =
new
byte
[in.length];
System.arraycopy(in, byteLen, tmp,
0
, in.length - byteLen);
System.arraycopy(in,
0
, tmp, in.length - byteLen, byteLen);
return
tmp;
}
}
|
d.SM3工具类
【SM3Digest.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
package
com.mlq.sm;
import
org.bouncycastle.util.encoders.Hex;
public
class
SM3Digest
{
/** SM3值的长度 */
private
static
final
int
BYTE_LENGTH =
32
;
/** SM3分组长度 */
private
static
final
int
BLOCK_LENGTH =
64
;
/** 缓冲区长度 */
private
static
final
int
BUFFER_LENGTH = BLOCK_LENGTH *
1
;
/** 缓冲区 */
private
byte
[] xBuf =
new
byte
[BUFFER_LENGTH];
/** 缓冲区偏移量 */
private
int
xBufOff;
/** 初始向量 */
private
byte
[] V = SM3.iv.clone();
private
int
cntBlock =
0
;
public
SM3Digest() {
}
public
SM3Digest(SM3Digest t)
{
System.arraycopy(t.xBuf,
0
,
this
.xBuf,
0
, t.xBuf.length);
this
.xBufOff = t.xBufOff;
System.arraycopy(t.V,
0
,
this
.V,
0
, t.V.length);
}
/**
* SM3结果输出
*
* @param out 保存SM3结构的缓冲区
* @param outOff 缓冲区偏移量
* @return
*/
public
int
doFinal(
byte
[] out,
int
outOff)
{
byte
[] tmp = doFinal();
System.arraycopy(tmp,
0
, out,
0
, tmp.length);
return
BYTE_LENGTH;
}
public
void
reset()
{
xBufOff =
0
;
cntBlock =
0
;
V = SM3.iv.clone();
}
/**
* 明文输入
*
* @param in
* 明文输入缓冲区
* @param inOff
* 缓冲区偏移量
* @param len
* 明文长度
*/
public
void
update(
byte
[] in,
int
inOff,
int
len)
{
int
partLen = BUFFER_LENGTH - xBufOff;
int
inputLen = len;
int
dPos = inOff;
if
(partLen < inputLen)
{
System.arraycopy(in, dPos, xBuf, xBufOff, partLen);
inputLen -= partLen;
dPos += partLen;
doUpdate();
while
(inputLen > BUFFER_LENGTH)
{
System.arraycopy(in, dPos, xBuf,
0
, BUFFER_LENGTH);
inputLen -= BUFFER_LENGTH;
dPos += BUFFER_LENGTH;
doUpdate();
}
}
System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);
xBufOff += inputLen;
}
private
void
doUpdate()
{
byte
[] B =
new
byte
[BLOCK_LENGTH];
for
(
int
i =
0
; i < BUFFER_LENGTH; i += BLOCK_LENGTH)
{
System.arraycopy(xBuf, i, B,
0
, B.length);
doHash(B);
}
xBufOff =
0
;
}
private
void
doHash(
byte
[] B)
{
byte
[] tmp = SM3.CF(V, B);
System.arraycopy(tmp,
0
, V,
0
, V.length);
cntBlock++;
}
private
byte
[] doFinal()
{
byte
[] B =
new
byte
[BLOCK_LENGTH];
byte
[] buffer =
new
byte
[xBufOff];
System.arraycopy(xBuf,
0
, buffer,
0
, buffer.length);
byte
[] tmp = SM3.padding(buffer, cntBlock);
for
(
int
i =
0
; i < tmp.length; i += BLOCK_LENGTH)
{
System.arraycopy(tmp, i, B,
0
, B.length);
doHash(B);
}
return
V;
}
public
void
update(
byte
in)
{
byte
[] buffer =
new
byte
[] { in };
update(buffer,
0
,
1
);
}
public
int
getDigestSize()
{
return
BYTE_LENGTH;
}
public
static
void
main(String[] args)
{
byte
[] md =
new
byte
[
32
];
byte
[] msg1 =
"ererfeiisgod"
.getBytes();
SM3Digest sm3 =
new
SM3Digest();
sm3.update(msg1,
0
, msg1.length);
sm3.doFinal(md,
0
);
String s =
new
String(Hex.encode(md));
System.out.println(s.toUpperCase());
}
}
|
e.工具类
【Util.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
|
package
com.mlq.sm;
import
java.math.BigInteger;
public
class
Util
{
/**
* 整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个整型数据
* @return 4个字节的自己数组
*/
public
static
byte
[] intToBytes(
int
num)
{
byte
[] bytes =
new
byte
[
4
];
bytes[
0
] = (
byte
) (
0xff
& (num >>
0
));
bytes[
1
] = (
byte
) (
0xff
& (num >>
8
));
bytes[
2
] = (
byte
) (
0xff
& (num >>
16
));
bytes[
3
] = (
byte
) (
0xff
& (num >>
24
));
return
bytes;
}
/**
* 四个字节的字节数据转换成一个整形数据
*
* @param bytes 4个字节的字节数组
* @return 一个整型数据
*/
public
static
int
byteToInt(
byte
[] bytes)
{
int
num =
0
;
int
temp;
temp = (
0x000000ff
& (bytes[
0
])) <<
0
;
num = num | temp;
temp = (
0x000000ff
& (bytes[
1
])) <<
8
;
num = num | temp;
temp = (
0x000000ff
& (bytes[
2
])) <<
16
;
num = num | temp;
temp = (
0x000000ff
& (bytes[
3
])) <<
24
;
num = num | temp;
return
num;
}
/**
* 长整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个长整型数据
* @return 4个字节的自己数组
*/
public
static
byte
[] longToBytes(
long
num)
{
byte
[] bytes =
new
byte
[
8
];
for
(
int
i =
0
; i <
8
; i++)
{
bytes[i] = (
byte
) (
0xff
& (num >> (i *
8
)));
}
return
bytes;
}
/**
* 大数字转换字节流(字节数组)型数据
*
* @param n
* @return
*/
public
static
byte
[] byteConvert32Bytes(BigInteger n)
{
byte
tmpd[] = (
byte
[])
null
;
if
(n ==
null
)
{
return
null
;
}
if
(n.toByteArray().length ==
33
)
{
tmpd =
new
byte
[
32
];
System.arraycopy(n.toByteArray(),
1
, tmpd,
0
,
32
);
}
else
if
(n.toByteArray().length ==
32
)
{
tmpd = n.toByteArray();
}
else
{
tmpd =
new
byte
[
32
];
for
(
int
i =
0
; i <
32
- n.toByteArray().length; i++)
{
tmpd[i] =
0
;
}
System.arraycopy(n.toByteArray(),
0
, tmpd,
32
- n.toByteArray().length, n.toByteArray().length);
}
return
tmpd;
}
/**
* 换字节流(字节数组)型数据转大数字
*
* @param b
* @return
*/
public
static
BigInteger byteConvertInteger(
byte
[] b)
{
if
(b[
0
] <
0
)
{
byte
[] temp =
new
byte
[b.length +
1
];
temp[
0
] =
0
;
System.arraycopy(b,
0
, temp,
1
, b.length);
return
new
BigInteger(temp);
}
return
new
BigInteger(b);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @return
*/
public
static
String getHexString(
byte
[] bytes)
{
return
getHexString(bytes,
true
);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @param upperCase
* @return
*/
public
static
String getHexString(
byte
[] bytes,
boolean
upperCase)
{
String ret =
""
;
for
(
int
i =
0
; i < bytes.length; i++)
{
ret += Integer.toString((bytes[i] &
0xff
) +
0x100
,
16
).substring(
1
);
}
return
upperCase ? ret.toUpperCase() : ret;
}
/**
* 打印十六进制字符串
*
* @param bytes
*/
public
static
void
printHexString(
byte
[] bytes)
{
for
(
int
i =
0
; i < bytes.length; i++)
{
String hex = Integer.toHexString(bytes[i] &
0xFF
);
if
(hex.length() ==
1
)
{
hex =
'0'
+ hex;
}
System.out.print(
"0x"
+ hex.toUpperCase() +
","
);
}
System.out.println(
""
);
}
/**
* Convert hex string to byte[]
*
* @param hexString
* the hex string
* @return byte[]
*/
public
static
byte
[] hexStringToBytes(String hexString)
{
if
(hexString ==
null
|| hexString.equals(
""
))
{
return
null
;
}
hexString = hexString.toUpperCase();
int
length = hexString.length() /
2
;
char
[] hexChars = hexString.toCharArray();
byte
[] d =
new
byte
[length];
for
(
int
i =
0
; i < length; i++)
{
int
pos = i *
2
;
d[i] = (
byte
) (charToByte(hexChars[pos]) <<
4
| charToByte(hexChars[pos +
1
]));
}
return
d;
}
/**
* Convert char to byte
*
* @param c
* char
* @return byte
*/
public
static
byte
charToByte(
char
c)
{
return
(
byte
)
"0123456789ABCDEF"
.indexOf(c);
}
/**
* 用于建立十六进制字符的输出的小写字符数组
*/
private
static
final
char
[] DIGITS_LOWER = {
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
};
/**
* 用于建立十六进制字符的输出的大写字符数组
*/
private
static
final
char
[] DIGITS_UPPER = {
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
};
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @return 十六进制char[]
*/
public
static
char
[] encodeHex(
byte
[] data) {
return
encodeHex(data,
true
);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public
static
char
[] encodeHex(
byte
[] data,
boolean
toLowerCase) {
return
encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制char[]
*/
protected
static
char
[] encodeHex(
byte
[] data,
char
[] toDigits) {
int
l = data.length;
char
[] out =
new
char
[l <<
1
];
// two characters form the hex value.
for
(
int
i =
0
, j =
0
; i < l; i++) {
out[j++] = toDigits[(
0xF0
& data[i]) >>>
4
];
out[j++] = toDigits[
0x0F
& data[i]];
}
return
out;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @return 十六进制String
*/
public
static
String encodeHexString(
byte
[] data) {
return
encodeHexString(data,
true
);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public
static
String encodeHexString(
byte
[] data,
boolean
toLowerCase) {
return
encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制String
*/
protected
static
String encodeHexString(
byte
[] data,
char
[] toDigits) {
return
new
String(encodeHex(data, toDigits));
}
/**
* 将十六进制字符数组转换为字节数组
*
* @param data 十六进制char[]
* @return byte[]
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
*/
public
static
byte
[] decodeHex(
char
[] data) {
int
len = data.length;
if
((len &
0x01
) !=
0
) {
throw
new
RuntimeException(
"Odd number of characters."
);
}
byte
[] out =
new
byte
[len >>
1
];
// two characters form the hex value.
for
(
int
i =
0
, j =
0
; j < len; i++) {
int
f = toDigit(data[j], j) <<
4
;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (
byte
) (f &
0xFF
);
}
return
out;
}
/**
* 将十六进制字符转换成一个整数
*
* @param ch 十六进制char
* @param index 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
*/
protected
static
int
toDigit(
char
ch,
int
index) {
int
digit = Character.digit(ch,
16
);
if
(digit == -
1
) {
throw
new
RuntimeException(
"Illegal hexadecimal character "
+ ch
+
" at index "
+ index);
}
return
digit;
}
/**
* 数字字符串转ASCII码字符串
*
* @param String
* 字符串
* @return ASCII字符串
*/
public
static
String StringToAsciiString(String content) {
String result =
""
;
int
max = content.length();
for
(
int
i =
0
; i < max; i++) {
char
c = content.charAt(i);
String b = Integer.toHexString(c);
result = result + b;
}
return
result;
}
/**
* 十六进制转字符串
*
* @param hexString
* 十六进制字符串
* @param encodeType
* 编码类型4:Unicode,2:普通编码
* @return 字符串
*/
public
static
String hexStringToString(String hexString,
int
encodeType) {
String result =
""
;
int
max = hexString.length() / encodeType;
for
(
int
i =
0
; i < max; i++) {
char
c = (
char
) hexStringToAlgorism(hexString
.substring(i * encodeType, (i +
1
) * encodeType));
result += c;
}
return
result;
}
/**
* 十六进制字符串装十进制
*
* @param hex
* 十六进制字符串
* @return 十进制数值
*/
public
static
int
hexStringToAlgorism(String hex) {
hex = hex.toUpperCase();
int
max = hex.length();
int
result =
0
;
for
(
int
i = max; i >
0
; i--) {
char
c = hex.charAt(i -
1
);
int
algorism =
0
;
if
(c >=
'0'
&& c <=
'9'
) {
algorism = c -
'0'
;
}
else
{
algorism = c -
55
;
}
result += Math.pow(
16
, max - i) * algorism;
}
return
result;
}
/**
* 十六转二进制
*
* @param hex
* 十六进制字符串
* @return 二进制字符串
*/
public
static
String hexStringToBinary(String hex) {
hex = hex.toUpperCase();
String result =
""
;
int
max = hex.length();
for
(
int
i =
0
; i < max; i++) {
char
c = hex.charAt(i);
switch
(c) {
case
'0'
:
result +=
"0000"
;
break
;
case
'1'
:
result +=
"0001"
;
break
;
case
'2'
:
result +=
"0010"
;
break
;
case
'3'
:
result +=
"0011"
;
break
;
case
'4'
:
result +=
"0100"
;
break
;
case
'5'
:
result +=
"0101"
;
break
;
case
'6'
:
result +=
"0110"
;
break
;
case
'7'
:
result +=
"0111"
;
break
;
case
'8'
:
result +=
"1000"
;
break
;
case
'9'
:
result +=
"1001"
;
break
;
case
'A'
:
result +=
"1010"
;
break
;
case
'B'
:
result +=
"1011"
;
break
;
case
'C'
:
result +=
"1100"
;
break
;
case
'D'
:
result +=
"1101"
;
break
;
case
'E'
:
result +=
"1110"
;
break
;
case
'F'
:
result +=
"1111"
;
break
;
}
}
return
result;
}
/**
* ASCII码字符串转数字字符串
*
* @param String
* ASCII字符串
* @return 字符串
*/
public
static
String AsciiStringToString(String content) {
String result =
""
;
int
length = content.length() /
2
;
for
(
int
i =
0
; i < length; i++) {
String c = content.substring(i *
2
, i *
2
+
2
);
int
a = hexStringToAlgorism(c);
char
b = (
char
) a;
String d = String.valueOf(b);
result += d;
}
return
result;
}
/**
* 将十进制转换为指定长度的十六进制字符串
*
* @param algorism
* int 十进制数字
* @param maxLength
* int 转换后的十六进制字符串长度
* @return String 转换后的十六进制字符串
*/
public
static
String algorismToHexString(
int
algorism,
int
maxLength) {
String result =
""
;
result = Integer.toHexString(algorism);
if
(result.length() %
2
==
1
) {
result =
"0"
+ result;
}
return
patchHexString(result.toUpperCase(), maxLength);
}
/**
* 字节数组转为普通字符串(ASCII对应的字符)
*
* @param bytearray
* byte[]
* @return String
*/
public
static
String byteToString(
byte
[] bytearray) {
String result =
""
;
char
temp;
int
length = bytearray.length;
for
(
int
i =
0
; i < length; i++) {
temp = (
char
) bytearray[i];
result += temp;
}
return
result;
}
/**
* 二进制字符串转十进制
*
* @param binary
* 二进制字符串
* @return 十进制数值
*/
public
static
int
binaryToAlgorism(String binary) {
int
max = binary.length();
int
result =
0
;
for
(
int
i = max; i >
0
; i--) {
char
c = binary.charAt(i -
1
);
int
algorism = c -
'0'
;
result += Math.pow(
2
, max - i) * algorism;
}
return
result;
}
/**
* 十进制转换为十六进制字符串
*
* @param algorism
* int 十进制的数字
* @return String 对应的十六进制字符串
*/
public
static
String algorismToHEXString(
int
algorism) {
String result =
""
;
result = Integer.toHexString(algorism);
if
(result.length() %
2
==
1
) {
result =
"0"
+ result;
}
result = result.toUpperCase();
return
result;
}
/**
* HEX字符串前补0,主要用于长度位数不足。
*
* @param str
* String 需要补充长度的十六进制字符串
* @param maxLength
* int 补充后十六进制字符串的长度
* @return 补充结果
*/
static
public
String patchHexString(String str,
int
maxLength) {
String temp =
""
;
for
(
int
i =
0
; i < maxLength - str.length(); i++) {
temp =
"0"
+ temp;
}
str = (temp + str).substring(
0
, maxLength);
return
str;
}
/**
* 将一个字符串转换为int
*
* @param s
* String 要转换的字符串
* @param defaultInt
* int 如果出现异常,默认返回的数字
* @param radix
* int 要转换的字符串是什么进制的,如16 8 10.
* @return int 转换后的数字
*/
public
static
int
parseToInt(String s,
int
defaultInt,
int
radix) {
int
i =
0
;
try
{
i = Integer.parseInt(s, radix);
}
catch
(NumberFormatException ex) {
i = defaultInt;
}
return
i;
}
/**
* 将一个十进制形式的数字字符串转换为int
*
* @param s
* String 要转换的字符串
* @param defaultInt
* int 如果出现异常,默认返回的数字
* @return int 转换后的数字
*/
public
static
int
parseToInt(String s,
int
defaultInt) {
int
i =
0
;
try
{
i = Integer.parseInt(s);
}
catch
(NumberFormatException ex) {
i = defaultInt;
}
return
i;
}
/**
* 十六进制串转化为byte数组
*
* @return the array of byte
*/
public
static
byte
[] hexToByte(String hex)
throws
IllegalArgumentException {
if
(hex.length() %
2
!=
0
) {
throw
new
IllegalArgumentException();
}
char
[] arr = hex.toCharArray();
byte
[] b =
new
byte
[hex.length() /
2
];
for
(
int
i =
0
, j =
0
, l = hex.length(); i < l; i++, j++) {
String swap =
""
+ arr[i++] + arr[i];
int
byteint = Integer.parseInt(swap,
16
) &
0xFF
;
b[j] =
new
Integer(byteint).byteValue();
}
return
b;
}
/**
* 字节数组转换为十六进制字符串
*
* @param b
* byte[] 需要转换的字节数组
* @return String 十六进制字符串
*/
public
static
String byteToHex(
byte
b[]) {
if
(b ==
null
) {
throw
new
IllegalArgumentException(
"Argument b ( byte array ) is null! "
);
}
String hs =
""
;
String stmp =
""
;
for
(
int
n =
0
; n < b.length; n++) {
stmp = Integer.toHexString(b[n] &
0xff
);
if
(stmp.length() ==
1
) {
hs = hs +
"0"
+ stmp;
}
else
{
hs = hs + stmp;
}
}
return
hs.toUpperCase();
}
public
static
byte
[] subByte(
byte
[] input,
int
startIndex,
int
length) {
byte
[] bt =
new
byte
[length];
for
(
int
i =
0
; i < length; i++) {
bt[i] = input[i + startIndex];
}
return
bt;
}
}
|
2.SM4
直接上代码:
a.SM4主类
【SM4.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
|
package
com.mlq.sm;
import
java.io.ByteArrayInputStream;
import
java.io.ByteArrayOutputStream;
public
class
SM4
{
public
static
final
int
SM4_ENCRYPT =
1
;
public
static
final
int
SM4_DECRYPT =
0
;
private
long
GET_ULONG_BE(
byte
[] b,
int
i)
{
long
n = (
long
)(b[i] &
0xff
) <<
24
| (
long
)((b[i +
1
] &
0xff
) <<
16
) | (
long
)((b[i +
2
] &
0xff
) <<
8
) | (
long
)(b[i +
3
] &
0xff
) & 0xffffffffL;
return
n;
}
private
void
PUT_ULONG_BE(
long
n,
byte
[] b,
int
i)
{
b[i] = (
byte
)(
int
)(
0xFF
& n >>
24
);
b[i +
1
] = (
byte
)(
int
)(
0xFF
& n >>
16
);
b[i +
2
] = (
byte
)(
int
)(
0xFF
& n >>
8
);
b[i +
3
] = (
byte
)(
int
)(
0xFF
& n);
}
private
long
SHL(
long
x,
int
n)
{
return
(x &
0xFFFFFFFF
) << n;
}
private
long
ROTL(
long
x,
int
n)
{
return
SHL(x, n) | x >> (
32
- n);
}
private
void
SWAP(
long
[] sk,
int
i)
{
long
t = sk[i];
sk[i] = sk[(
31
- i)];
sk[(
31
- i)] = t;
}
public
static
final
byte
[] SboxTable = { (
byte
)
0xd6
, (
byte
)
0x90
, (
byte
)
0xe9
, (
byte
)
0xfe
,
(
byte
)
0xcc
, (
byte
)
0xe1
,
0x3d
, (
byte
)
0xb7
,
0x16
, (
byte
)
0xb6
,
0x14
, (
byte
)
0xc2
,
0x28
, (
byte
)
0xfb
,
0x2c
,
0x05
,
0x2b
,
0x67
,
(
byte
)
0x9a
,
0x76
,
0x2a
, (
byte
)
0xbe
,
0x04
, (
byte
)
0xc3
,
(
byte
)
0xaa
,
0x44
,
0x13
,
0x26
,
0x49
, (
byte
)
0x86
,
0x06
,
(
byte
)
0x99
, (
byte
)
0x9c
,
0x42
,
0x50
, (
byte
)
0xf4
, (
byte
)
0x91
,
(
byte
)
0xef
, (
byte
)
0x98
,
0x7a
,
0x33
,
0x54
,
0x0b
,
0x43
,
(
byte
)
0xed
, (
byte
)
0xcf
, (
byte
)
0xac
,
0x62
, (
byte
)
0xe4
,
(
byte
)
0xb3
,
0x1c
, (
byte
)
0xa9
, (
byte
)
0xc9
,
0x08
, (
byte
)
0xe8
,
(
byte
)
0x95
, (
byte
)
0x80
, (
byte
)
0xdf
, (
byte
)
0x94
, (
byte
)
0xfa
,
0x75
, (
byte
)
0x8f
,
0x3f
, (
byte
)
0xa6
,
0x47
,
0x07
, (
byte
)
0xa7
,
(
byte
)
0xfc
, (
byte
)
0xf3
,
0x73
,
0x17
, (
byte
)
0xba
, (
byte
)
0x83
,
0x59
,
0x3c
,
0x19
, (
byte
)
0xe6
, (
byte
)
0x85
,
0x4f
, (
byte
)
0xa8
,
0x68
,
0x6b
, (
byte
)
0x81
, (
byte
)
0xb2
,
0x71
,
0x64
, (
byte
)
0xda
,
(
byte
)
0x8b
, (
byte
)
0xf8
, (
byte
)
0xeb
,
0x0f
,
0x4b
,
0x70
,
0x56
,
(
byte
)
0x9d
,
0x35
,
0x1e
,
0x24
,
0x0e
,
0x5e
,
0x63
,
0x58
, (
byte
)
0xd1
,
(
byte
)
0xa2
,
0x25
,
0x22
,
0x7c
,
0x3b
,
0x01
,
0x21
,
0x78
, (
byte
)
0x87
,
(
byte
)
0xd4
,
0x00
,
0x46
,
0x57
, (
byte
)
0x9f
, (
byte
)
0xd3
,
0x27
,
0x52
,
0x4c
,
0x36
,
0x02
, (
byte
)
0xe7
, (
byte
)
0xa0
, (
byte
)
0xc4
,
(
byte
)
0xc8
, (
byte
)
0x9e
, (
byte
)
0xea
, (
byte
)
0xbf
, (
byte
)
0x8a
,
(
byte
)
0xd2
,
0x40
, (
byte
)
0xc7
,
0x38
, (
byte
)
0xb5
, (
byte
)
0xa3
,
(
byte
)
0xf7
, (
byte
)
0xf2
, (
byte
)
0xce
, (
byte
)
0xf9
,
0x61
,
0x15
,
(
byte
)
0xa1
, (
byte
)
0xe0
, (
byte
)
0xae
,
0x5d
, (
byte
)
0xa4
,
(
byte
)
0x9b
,
0x34
,
0x1a
,
0x55
, (
byte
)
0xad
, (
byte
)
0x93
,
0x32
,
0x30
, (
byte
)
0xf5
, (
byte
)
0x8c
, (
byte
)
0xb1
, (
byte
)
0xe3
,
0x1d
,
(
byte
)
0xf6
, (
byte
)
0xe2
,
0x2e
, (
byte
)
0x82
,
0x66
, (
byte
)
0xca
,
0x60
, (
byte
)
0xc0
,
0x29
,
0x23
, (
byte
)
0xab
,
0x0d
,
0x53
,
0x4e
,
0x6f
,
(
byte
)
0xd5
, (
byte
)
0xdb
,
0x37
,
0x45
, (
byte
)
0xde
, (
byte
)
0xfd
,
(
byte
)
0x8e
,
0x2f
,
0x03
, (
byte
)
0xff
,
0x6a
,
0x72
,
0x6d
,
0x6c
,
0x5b
,
0x51
, (
byte
)
0x8d
,
0x1b
, (
byte
)
0xaf
, (
byte
)
0x92
, (
byte
)
0xbb
,
(
byte
)
0xdd
, (
byte
)
0xbc
,
0x7f
,
0x11
, (
byte
)
0xd9
,
0x5c
,
0x41
,
0x1f
,
0x10
,
0x5a
, (
byte
)
0xd8
,
0x0a
, (
byte
)
0xc1
,
0x31
,
(
byte
)
0x88
, (
byte
)
0xa5
, (
byte
)
0xcd
,
0x7b
, (
byte
)
0xbd
,
0x2d
,
0x74
, (
byte
)
0xd0
,
0x12
, (
byte
)
0xb8
, (
byte
)
0xe5
, (
byte
)
0xb4
,
(
byte
)
0xb0
, (
byte
)
0x89
,
0x69
, (
byte
)
0x97
,
0x4a
,
0x0c
,
(
byte
)
0x96
,
0x77
,
0x7e
,
0x65
, (
byte
)
0xb9
, (
byte
)
0xf1
,
0x09
,
(
byte
)
0xc5
,
0x6e
, (
byte
)
0xc6
, (
byte
)
0x84
,
0x18
, (
byte
)
0xf0
,
0x7d
, (
byte
)
0xec
,
0x3a
, (
byte
)
0xdc
,
0x4d
,
0x20
,
0x79
,
(
byte
)
0xee
,
0x5f
,
0x3e
, (
byte
)
0xd7
, (
byte
)
0xcb
,
0x39
,
0x48
};
public
static
final
int
[] FK = {
0xa3b1bac6
,
0x56aa3350
,
0x677d9197
,
0xb27022dc
};
public
static
final
int
[] CK = {
0x00070e15
,
0x1c232a31
,
0x383f464d
,
0x545b6269
,
0x70777e85
,
0x8c939aa1
,
0xa8afb6bd
,
0xc4cbd2d9
,
0xe0e7eef5
,
0xfc030a11
,
0x181f262d
,
0x343b4249
,
0x50575e65
,
0x6c737a81
,
0x888f969d
,
0xa4abb2b9
,
0xc0c7ced5
,
0xdce3eaf1
,
0xf8ff060d
,
0x141b2229
,
0x30373e45
,
0x4c535a61
,
0x686f767d
,
0x848b9299
,
0xa0a7aeb5
,
0xbcc3cad1
,
0xd8dfe6ed
,
0xf4fb0209
,
0x10171e25
,
0x2c333a41
,
0x484f565d
,
0x646b7279
};
private
byte
sm4Sbox(
byte
inch)
{
int
i = inch &
0xFF
;
byte
retVal = SboxTable[i];
return
retVal;
}
private
long
sm4Lt(
long
ka)
{
long
bb = 0L;
long
c = 0L;
byte
[] a =
new
byte
[
4
];
byte
[] b =
new
byte
[
4
];
PUT_ULONG_BE(ka, a,
0
);
b[
0
] = sm4Sbox(a[
0
]);
b[
1
] = sm4Sbox(a[
1
]);
b[
2
] = sm4Sbox(a[
2
]);
b[
3
] = sm4Sbox(a[
3
]);
bb = GET_ULONG_BE(b,
0
);
c = bb ^ ROTL(bb,
2
) ^ ROTL(bb,
10
) ^ ROTL(bb,
18
) ^ ROTL(bb,
24
);
return
c;
}
private
long
sm4F(
long
x0,
long
x1,
long
x2,
long
x3,
long
rk)
{
return
x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
}
private
long
sm4CalciRK(
long
ka)
{
long
bb = 0L;
long
rk = 0L;
byte
[] a =
new
byte
[
4
];
byte
[] b =
new
byte
[
4
];
PUT_ULONG_BE(ka, a,
0
);
b[
0
] = sm4Sbox(a[
0
]);
b[
1
] = sm4Sbox(a[
1
]);
b[
2
] = sm4Sbox(a[
2
]);
b[
3
] = sm4Sbox(a[
3
]);
bb = GET_ULONG_BE(b,
0
);
rk = bb ^ ROTL(bb,
13
) ^ ROTL(bb,
23
);
return
rk;
}
private
void
sm4_setkey(
long
[] SK,
byte
[] key)
{
long
[] MK =
new
long
[
4
];
long
[] k =
new
long
[
36
];
int
i =
0
;
MK[
0
] = GET_ULONG_BE(key,
0
);
MK[
1
] = GET_ULONG_BE(key,
4
);
MK[
2
] = GET_ULONG_BE(key,
8
);
MK[
3
] = GET_ULONG_BE(key,
12
);
k[
0
] = MK[
0
] ^ (
long
) FK[
0
];
k[
1
] = MK[
1
] ^ (
long
) FK[
1
];
k[
2
] = MK[
2
] ^ (
long
) FK[
2
];
k[
3
] = MK[
3
] ^ (
long
) FK[
3
];
for
(; i <
32
; i++)
{
k[(i +
4
)] = (k[i] ^ sm4CalciRK(k[(i +
1
)] ^ k[(i +
2
)] ^ k[(i +
3
)] ^ (
long
) CK[i]));
SK[i] = k[(i +
4
)];
}
}
private
void
sm4_one_round(
long
[] sk,
byte
[] input,
byte
[] output)
{
int
i =
0
;
long
[] ulbuf =
new
long
[
36
];
ulbuf[
0
] = GET_ULONG_BE(input,
0
);
ulbuf[
1
] = GET_ULONG_BE(input,
4
);
ulbuf[
2
] = GET_ULONG_BE(input,
8
);
ulbuf[
3
] = GET_ULONG_BE(input,
12
);
while
(i <
32
)
{
ulbuf[(i +
4
)] = sm4F(ulbuf[i], ulbuf[(i +
1
)], ulbuf[(i +
2
)], ulbuf[(i +
3
)], sk[i]);
i++;
}
PUT_ULONG_BE(ulbuf[
35
], output,
0
);
PUT_ULONG_BE(ulbuf[
34
], output,
4
);
PUT_ULONG_BE(ulbuf[
33
], output,
8
);
PUT_ULONG_BE(ulbuf[
32
], output,
12
);
}
private
byte
[] padding(
byte
[] input,
int
mode)
{
if
(input ==
null
)
{
return
null
;
}
byte
[] ret = (
byte
[])
null
;
if
(mode == SM4_ENCRYPT)
{
int
p =
16
- input.length %
16
;
ret =
new
byte
[input.length + p];
System.arraycopy(input,
0
, ret,
0
, input.length);
for
(
int
i =
0
; i < p; i++)
{
ret[input.length + i] = (
byte
) p;
}
}
else
{
int
p = input[input.length -
1
];
ret =
new
byte
[input.length - p];
System.arraycopy(input,
0
, ret,
0
, input.length - p);
}
return
ret;
}
public
void
sm4_setkey_enc(SM4_Context ctx,
byte
[] key)
throws
Exception
{
if
(ctx ==
null
)
{
throw
new
Exception(
"ctx is null!"
);
}
if
(key ==
null
|| key.length !=
16
)
{
throw
new
Exception(
"key error!"
);
}
ctx.mode = SM4_ENCRYPT;
sm4_setkey(ctx.sk, key);
}
public
void
sm4_setkey_dec(SM4_Context ctx,
byte
[] key)
throws
Exception
{
if
(ctx ==
null
)
{
throw
new
Exception(
"ctx is null!"
);
}
if
(key ==
null
|| key.length !=
16
)
{
throw
new
Exception(
"key error!"
);
}
int
i =
0
;
ctx.mode = SM4_DECRYPT;
sm4_setkey(ctx.sk, key);
for
(i =
0
; i <
16
; i++)
{
SWAP(ctx.sk, i);
}
}
public
byte
[] sm4_crypt_ecb(SM4_Context ctx,
byte
[] input)
throws
Exception
{
if
(input ==
null
)
{
throw
new
Exception(
"input is null!"
);
}
if
((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT))
{
input = padding(input, SM4_ENCRYPT);
}
int
length = input.length;
ByteArrayInputStream bins =
new
ByteArrayInputStream(input);
ByteArrayOutputStream bous =
new
ByteArrayOutputStream();
for
(; length >
0
; length -=
16
)
{
byte
[] in =
new
byte
[
16
];
byte
[] out =
new
byte
[
16
];
bins.read(in);
sm4_one_round(ctx.sk, in, out);
bous.write(out);
}
byte
[] output = bous.toByteArray();
if
(ctx.isPadding && ctx.mode == SM4_DECRYPT)
{
output = padding(output, SM4_DECRYPT);
}
bins.close();
bous.close();
return
output;
}
public
byte
[] sm4_crypt_cbc(SM4_Context ctx,
byte
[] iv,
byte
[] input)
throws
Exception
{
if
(iv ==
null
|| iv.length !=
16
)
{
throw
new
Exception(
"iv error!"
);
}
if
(input ==
null
)
{
throw
new
Exception(
"input is null!"
);
}
if
(ctx.isPadding && ctx.mode == SM4_ENCRYPT)
{
input = padding(input, SM4_ENCRYPT);
}
int
i =
0
;
int
length = input.length;
ByteArrayInputStream bins =
new
ByteArrayInputStream(input);
ByteArrayOutputStream bous =
new
ByteArrayOutputStream();
if
(ctx.mode == SM4_ENCRYPT)
{
for
(; length >
0
; length -=
16
)
{
byte
[] in =
new
byte
[
16
];
byte
[] out =
new
byte
[
16
];
byte
[] out1 =
new
byte
[
16
];
bins.read(in);
for
(i =
0
; i <
16
; i++)
{
out[i] = ((
byte
) (in[i] ^ iv[i]));
}
sm4_one_round(ctx.sk, out, out1);
System.arraycopy(out1,
0
, iv,
0
,
16
);
bous.write(out1);
}
}
else
{
byte
[] temp =
new
byte
[
16
];
for
(; length >
0
; length -=
16
)
{
byte
[] in =
new
byte
[
16
];
byte
[] out =
new
byte
[
16
];
byte
[] out1 =
new
byte
[
16
];
bins.read(in);
System.arraycopy(in,
0
, temp,
0
,
16
);
sm4_one_round(ctx.sk, in, out);
for
(i =
0
; i <
16
; i++)
{
out1[i] = ((
byte
) (out[i] ^ iv[i]));
}
System.arraycopy(temp,
0
, iv,
0
,
16
);
bous.write(out1);
}
}
byte
[] output = bous.toByteArray();
if
(ctx.isPadding && ctx.mode == SM4_DECRYPT)
{
output = padding(output, SM4_DECRYPT);
}
bins.close();
bous.close();
return
output;
}
}
|
b.SM4实体类
【SM4_Context.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package
com.mlq.sm;
public
class
SM4_Context
{
public
int
mode;
public
long
[] sk;
public
boolean
isPadding;
public
SM4_Context()
{
this
.mode =
1
;
this
.isPadding =
true
;
this
.sk =
new
long
[
32
];
}
}
|
c.SM4工具类(这里的PaddingMode采用的是PKCS7)
【SM4Utils.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
package
com.mlq.sm;
import
java.io.IOException;
import
java.util.regex.Matcher;
import
java.util.regex.Pattern;
import
sun.misc.BASE64Decoder;
import
sun.misc.BASE64Encoder;
public
class
SM4Utils
{
private
String secretKey =
""
;
private
String iv =
""
;
private
boolean
hexString =
false
;
public
SM4Utils()
{
}
public
String encryptData_ECB(String plainText)
{
try
{
SM4_Context ctx =
new
SM4_Context();
ctx.isPadding =
true
;
ctx.mode = SM4.SM4_ENCRYPT;
byte
[] keyBytes;
if
(hexString)
{
keyBytes = Util.hexStringToBytes(secretKey);
}
else
{
keyBytes = secretKey.getBytes();
}
SM4 sm4 =
new
SM4();
sm4.sm4_setkey_enc(ctx, keyBytes);
byte
[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes(
"GBK"
));
String cipherText =
new
BASE64Encoder().encode(encrypted);
if
(cipherText !=
null
&& cipherText.trim().length() >
0
)
{
Pattern p = Pattern.compile(
"\\s*|\t|\r|\n"
);
Matcher m = p.matcher(cipherText);
cipherText = m.replaceAll(
""
);
}
return
cipherText;
}
catch
(Exception e)
{
e.printStackTrace();
return
null
;
}
}
public
String decryptData_ECB(String cipherText)
{
try
{
SM4_Context ctx =
new
SM4_Context();
ctx.isPadding =
true
;
ctx.mode = SM4.SM4_DECRYPT;
byte
[] keyBytes;
if
(hexString)
{
keyBytes = Util.hexStringToBytes(secretKey);
}
else
{
keyBytes = secretKey.getBytes();
}
SM4 sm4 =
new
SM4();
sm4.sm4_setkey_dec(ctx, keyBytes);
byte
[] decrypted = sm4.sm4_crypt_ecb(ctx,
new
BASE64Decoder().decodeBuffer(cipherText));
return
new
String(decrypted,
"GBK"
);
}
catch
(Exception e)
{
e.printStackTrace();
return
null
;
}
}
public
String encryptData_CBC(String plainText)
{
try
{
SM4_Context ctx =
new
SM4_Context();
ctx.isPadding =
true
;
ctx.mode = SM4.SM4_ENCRYPT;
byte
[] keyBytes;
byte
[] ivBytes;
if
(hexString)
{
keyBytes = Util.hexStringToBytes(secretKey);
ivBytes = Util.hexStringToBytes(iv);
}
else
{
keyBytes = secretKey.getBytes();
ivBytes = iv.getBytes();
}
SM4 sm4 =
new
SM4();
sm4.sm4_setkey_enc(ctx, keyBytes);
byte
[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes(
"GBK"
));
String cipherText =
new
BASE64Encoder().encode(encrypted);
if
(cipherText !=
null
&& cipherText.trim().length() >
0
)
{
Pattern p = Pattern.compile(
"\\s*|\t|\r|\n"
);
Matcher m = p.matcher(cipherText);
cipherText = m.replaceAll(
""
);
}
return
cipherText;
}
catch
(Exception e)
{
e.printStackTrace();
return
null
;
}
}
public
String decryptData_CBC(String cipherText)
{
try
{
SM4_Context ctx =
new
SM4_Context();
ctx.isPadding =
true
;
ctx.mode = SM4.SM4_DECRYPT;
byte
[] keyBytes;
byte
[] ivBytes;
if
(hexString)
{
keyBytes = Util.hexStringToBytes(secretKey);
ivBytes = Util.hexStringToBytes(iv);
}
else
{
keyBytes = secretKey.getBytes();
ivBytes = iv.getBytes();
}
SM4 sm4 =
new
SM4();
sm4.sm4_setkey_dec(ctx, keyBytes);
byte
[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes,
new
BASE64Decoder().decodeBuffer(cipherText));
return
new
String(decrypted,
"GBK"
);
}
catch
(Exception e)
{
e.printStackTrace();
return
null
;
}
}
public
static
void
main(String[] args)
throws
IOException
{
String plainText =
"ererfeiisgod"
;
SM4Utils sm4 =
new
SM4Utils();
sm4.secretKey =
"JeF8U9wHFOMfs2Y8"
;
sm4.hexString =
false
;
System.out.println(
"ECB模式"
);
String cipherText = sm4.encryptData_ECB(plainText);
System.out.println(
"密文: "
+ cipherText);
System.out.println(
""
);
plainText = sm4.decryptData_ECB(cipherText);
System.out.println(
"明文: "
+ plainText);
System.out.println(
""
);
System.out.println(
"CBC模式"
);
sm4.iv =
"UISwD9fW6cFh9SNS"
;
cipherText = sm4.encryptData_CBC(plainText);
System.out.println(
"密文: "
+ cipherText);
System.out.println(
""
);
plainText = sm4.decryptData_CBC(cipherText);
System.out.println(
"明文: "
+ plainText);
}
}
|