国密算法Go语言实现(详解)(五) ——SM4(分组算法)
原创代码:https://github.com/ZZMarquis/gm
引用时,请导入原创代码库。本文仅以注释方式详解代码逻辑,供学习研究使用。
对原创代码的修改内容
- 修改了部分常量、变量、结构体属性的名称, 以便与GO语言标准包规范相统一
- 加入中文注释,解释代码逻辑
注释者及联系邮箱
Paul Lee
paul_lee0919@163.com
// Encrypt() 为SM4的加密方法函数。
// (1) 校验输入消息字节数组的长度
// (2) 校验输出消息字节数组的长度
// (3) 调用分组消息处理函数processBlock()
func (c *sm4Cipher) Encrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("sm4: input not full block")
}
if len(dst) < BlockSize {
panic("sm4: output not full block")
}
processBlock(c.enc, src, dst)
}
Encrypt() 为SM4的加密方法函数。其中:
- (1) 校验输入消息字节数组的长度
- (2) 校验输出消息字节数组的长度
- (3) 调用分组消息处理函数processBlock( )
// Decrypt() 为SM4的解密方法函数。
// (1) 校验输入消息字节数组的长度
// (2) 校验输出消息字节数组的长度
// (3) 调用分组处理函数processBlock()
func (c *sm4Cipher) Decrypt(dst, src []byte) {
if len(src) < BlockSize {
panic("sm4: input not full block")
}
if len(dst) < BlockSize {
panic("sm4: output not full block")
}
processBlock(c.dec, src, dst)
}
Decrypt( ) 为SM4的解密方法函数。其中:
- (1) 校验输入消息字节数组的长度
- (2) 校验输出消息字节数组的长度
- (3) 调用分组数据处理函数processBlock( )
// tau() 为国标(6.2.(a))规定的Sbox非线性变换τ(.),其中:
// (1) 如果将Sbox二维表逐行展开为一维数组s[],则数组元素的序号就是Sbox行序号乘16加列序号;
// (2) 因为Sbox二维表本身为16x16的表,而1个字节存储单元能够存储8位二进制数,折算16进制就是2位16进制数;
// (3) 所以,若将1个字节所表示的二进制数字a,折算成16进制数字(假设为EF),然后将其高位E作为行坐标、将低位F作为列坐标,
// 则数字a就可以用来表示Sbox二维表中某个元素的行列坐标(E,F):
// (4) Sbox二维表中,坐标为(E,F)的元素展开成数组s[]后,其数组序号就是: Ex16 + F,这其实就是数字a的值;
// (5) 所以,根据非线性变换τ(.)的定义,Sbox(a)=s[a]
func tau(a uint32) uint32 {
var aArr [4