SM4 算法实现

SM4 介绍

SM4 算法是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》”。本质是一个对称分组加密算法,类似于 DES 或者 AES。它的的分组长度为 128bit,密钥长度为 128bit。算法先由已知秘钥生成轮秘钥 rk,然后与被 S-box 加密后的明文 X 进行 32 轮轮变换,生成密文。解密只需将轮秘钥倒序再进行 32 轮轮变换即可,代码仓库

具体实现

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
func S(a uint32) uint32 { // 通过S盒置换字
var aArr [4]byte
var bArr [4]byte
binary.BigEndian.PutUint32(aArr[:], a)
bArr[0] = sBox[aArr[0]]
bArr[1] = sBox[aArr[1]]
bArr[2] = sBox[aArr[2]]
bArr[3] = sBox[aArr[3]]
return binary.BigEndian.Uint32(bArr[:])
}

func L(b uint32) uint32 { // L变换
return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^
bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
}

func T(z uint32) uint32 { // T变换
return L(S(z))
}

func lRk(b uint32) uint32 { // rk的L变换
return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
}

func tRk(z uint32) uint32 { // rk的T变换
return lRk(S(z))
}

func reverse(a []uint32) { //反转数组
a[0], a[3] = a[3], a[0]
a[1], a[2] = a[2], a[1]
}

func expandKey(key []byte) []uint32 { // 生成轮秘钥rk
mK := make([]uint32, 4)
mK[0] = binary.BigEndian.Uint32(key[0:4]) // 将四个字节转为一个字
mK[1] = binary.BigEndian.Uint32(key[4:8])
mK[2] = binary.BigEndian.Uint32(key[8:12])
mK[3] = binary.BigEndian.Uint32(key[12:16])

k := make([]uint32, 36)
k[0] = mK[0] ^ fK[0] // 主密钥与中系统参数fk异或得到中间数据k
k[1] = mK[1] ^ fK[1]
k[2] = mK[2] ^ fK[2]
k[3] = mK[3] ^ fK[3]

rk := make([]uint32, 32)
for i := 0; i < 32; i++ { // 计算rk[i]
k[i+4] = k[i] ^ tRk(k[i+1]^k[i+2]^k[i+3]^cK[i])
rk[i] = k[i+4]
}
return rk
}

func initX(text []byte) []uint32 { // 初始化x
x := make([]uint32, 36)
x[0] = binary.BigEndian.Uint32(text[0:4])
x[1] = binary.BigEndian.Uint32(text[4:8])
x[2] = binary.BigEndian.Uint32(text[8:12])
x[3] = binary.BigEndian.Uint32(text[12:16])
return x
}

func encrypt(x []uint32, rk []uint32) []uint32 { // 加密操作:32次轮函数 + 1次反转
for i := 0; i < 32; i++ {
x[i+4] = x[i] ^ T(x[i+1]^x[i+2]^x[i+3]^rk[i])
}
reverse(x[32:])
return x[32:]
}

func decrypt(res []uint32, rk []uint32) []uint32 { // 解密操作:32次轮函数(rk 从后往前) + 1次反转
x := make([]uint32, 36)
x[0] = res[0] //将res转移为新的x
x[1] = res[1]
x[2] = res[2]
x[3] = res[3]
for i := 0; i < 32; i++ {
x[i+4] = x[i] ^ T(x[i+1]^x[i+2]^x[i+3]^rk[31-i])
}
reverse(x[32:])
return x[32:]
}

func Padding(text []byte, blockSize int) []byte { // 尾部填充
length := blockSize - len(text)%blockSize
padText := bytes.Repeat([]byte{byte(length)}, length)
return append(text, padText...)
}

func UnPadding(text []byte) []byte { // 删除填充
length := len(text)
padLength := int(text[length-1])
return text[:(length - padLength)]
}
© 2020 GitHub, Inc.