-
Notifications
You must be signed in to change notification settings - Fork 2
/
block.go
153 lines (138 loc) · 3.89 KB
/
block.go
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
package sm4
// [GM/T] SM4 GB/T 32907-2016
import (
"encoding/binary"
"math/bits"
)
/*
sm4/block.go sm4块加密与块解密
*/
type convert func(uint32) uint32
// sm4块加密
// Encrypt one block from src into dst, using the expanded key xk.
func encryptBlockGo(xk []uint32, dst, src []byte) {
_ = src[15] // early bounds check
_ = dst[15] // early bounds check
var b0, b1, b2, b3 uint32
// 切分明文块,获取4个字
b0 = binary.BigEndian.Uint32(src[0:4])
b1 = binary.BigEndian.Uint32(src[4:8])
b2 = binary.BigEndian.Uint32(src[8:12])
b3 = binary.BigEndian.Uint32(src[12:16])
// 1~4轮
b0 ^= t(b1 ^ b2 ^ b3 ^ xk[0])
b1 ^= t(b2 ^ b3 ^ b0 ^ xk[1])
b2 ^= t(b3 ^ b0 ^ b1 ^ xk[2])
b3 ^= t(b0 ^ b1 ^ b2 ^ xk[3])
// 5~8轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[4])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[5])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[6])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[7])
// 9~12轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[8])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[9])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[10])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[11])
// 13~16轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[12])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[13])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[14])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[15])
// 17~20轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[16])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[17])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[18])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[19])
// 21~24轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[20])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[21])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[22])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[23])
// 24~28轮
b0 ^= precompute_t(b1 ^ b2 ^ b3 ^ xk[24])
b1 ^= precompute_t(b2 ^ b3 ^ b0 ^ xk[25])
b2 ^= precompute_t(b3 ^ b0 ^ b1 ^ xk[26])
b3 ^= precompute_t(b0 ^ b1 ^ b2 ^ xk[27])
// 29~32轮
b0 ^= t(b1 ^ b2 ^ b3 ^ xk[28])
b1 ^= t(b2 ^ b3 ^ b0 ^ xk[29])
b2 ^= t(b3 ^ b0 ^ b1 ^ xk[30])
b3 ^= t(b0 ^ b1 ^ b2 ^ xk[31])
// 反序拼接
binary.BigEndian.PutUint32(dst[:], b3)
binary.BigEndian.PutUint32(dst[4:], b2)
binary.BigEndian.PutUint32(dst[8:], b1)
binary.BigEndian.PutUint32(dst[12:], b0)
}
// sm4密钥扩展
// Key expansion algorithm.
func expandKeyGo(key []byte, enc, dec []uint32) {
// Encryption key setup.
var i int
var mk []uint32
var k [rounds + 4]uint32
nk := len(key) / 4
mk = make([]uint32, nk)
for i = 0; i < nk; i++ {
mk[i] = binary.BigEndian.Uint32(key[4*i:])
k[i] = mk[i] ^ fk[i]
}
for i = 0; i < rounds; i++ {
// 合成置换再异或
k[i+4] = k[i] ^ t2(k[i+1]^k[i+2]^k[i+3]^ck[i])
enc[i] = k[i+4]
}
// Derive decryption key from encryption key.
if dec == nil {
return
}
for i = 0; i < rounds; i++ {
dec[i] = enc[rounds-1-i]
}
}
// sm4块解密
// 外部调用时需保证xk是逆序的轮密钥
// Decrypt one block from src into dst, using the expanded key xk.
func decryptBlockGo(xk []uint32, dst, src []byte) {
encryptBlockGo(xk, dst, src)
}
// 轮函数用线性变换函数
// L(B)
func l(b uint32) uint32 {
return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^ bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
}
// 密钥扩展用线性变换函数
// L'(B)
func l2(b uint32) uint32 {
return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
}
// 合成置换函数
func _t(in uint32, fn convert) uint32 {
var bytes [4]byte
binary.BigEndian.PutUint32(bytes[:], in)
// 使用s盒映射实现非线性变换
for i := 0; i < 4; i++ {
bytes[i] = sbox[bytes[i]]
}
// 调用线性变换函数
return fn(binary.BigEndian.Uint32(bytes[:]))
}
// 轮函数用合成置换函数
// T
func t(in uint32) uint32 {
return _t(in, l)
}
// 密钥扩展用合成置换函数
// T'
func t2(in uint32) uint32 {
return _t(in, l2)
}
// 优化的轮函数用合成置换函数
// 5~28轮使用
func precompute_t(in uint32) uint32 {
return sbox_t0[byte(in>>24)] ^
sbox_t1[byte(in>>16)] ^
sbox_t2[byte(in>>8)] ^
sbox_t3[byte(in)]
}