github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/sm4/block.go (about)

     1  package sm4
     2  
     3  // [GM/T] SM4 GB/T 32907-2016
     4  
     5  import (
     6  	"encoding/binary"
     7  	"math/bits"
     8  )
     9  
    10  /*
    11  sm4/block.go sm4块加密与块解密
    12  */
    13  
    14  type convert func(uint32) uint32
    15  
    16  // sm4块加密
    17  //
    18  //	Encrypt one block from src into dst, using the expanded key xk.
    19  func encryptBlockGo(xk []uint32, dst, src []byte) {
    20  	_ = src[15] // early bounds check
    21  	_ = dst[15] // early bounds check
    22  	var b0, b1, b2, b3 uint32
    23  	// 切分明文块,获取4个字
    24  	b0 = binary.BigEndian.Uint32(src[0:4])
    25  	b1 = binary.BigEndian.Uint32(src[4:8])
    26  	b2 = binary.BigEndian.Uint32(src[8:12])
    27  	b3 = binary.BigEndian.Uint32(src[12:16])
    28  	// 1~4轮
    29  	b0 ^= t(b1 ^ b2 ^ b3 ^ xk[0])
    30  	b1 ^= t(b2 ^ b3 ^ b0 ^ xk[1])
    31  	b2 ^= t(b3 ^ b0 ^ b1 ^ xk[2])
    32  	b3 ^= t(b0 ^ b1 ^ b2 ^ xk[3])
    33  	// 5~8轮
    34  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[4])
    35  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[5])
    36  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[6])
    37  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[7])
    38  	// 9~12轮
    39  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[8])
    40  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[9])
    41  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[10])
    42  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[11])
    43  	// 13~16轮
    44  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[12])
    45  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[13])
    46  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[14])
    47  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[15])
    48  	// 17~20轮
    49  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[16])
    50  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[17])
    51  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[18])
    52  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[19])
    53  	// 21~24轮
    54  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[20])
    55  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[21])
    56  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[22])
    57  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[23])
    58  	// 24~28轮
    59  	b0 ^= precomputeT(b1 ^ b2 ^ b3 ^ xk[24])
    60  	b1 ^= precomputeT(b2 ^ b3 ^ b0 ^ xk[25])
    61  	b2 ^= precomputeT(b3 ^ b0 ^ b1 ^ xk[26])
    62  	b3 ^= precomputeT(b0 ^ b1 ^ b2 ^ xk[27])
    63  	// 29~32轮
    64  	b0 ^= t(b1 ^ b2 ^ b3 ^ xk[28])
    65  	b1 ^= t(b2 ^ b3 ^ b0 ^ xk[29])
    66  	b2 ^= t(b3 ^ b0 ^ b1 ^ xk[30])
    67  	b3 ^= t(b0 ^ b1 ^ b2 ^ xk[31])
    68  	// 反序拼接
    69  	binary.BigEndian.PutUint32(dst[:], b3)
    70  	binary.BigEndian.PutUint32(dst[4:], b2)
    71  	binary.BigEndian.PutUint32(dst[8:], b1)
    72  	binary.BigEndian.PutUint32(dst[12:], b0)
    73  }
    74  
    75  // sm4密钥扩展
    76  //
    77  //	Key expansion algorithm.
    78  func expandKeyGo(key []byte, enc, dec []uint32) {
    79  	// Encryption key setup.
    80  	var i int
    81  	var mk []uint32
    82  	var k [rounds + 4]uint32
    83  	nk := len(key) / 4
    84  	mk = make([]uint32, nk)
    85  	for i = 0; i < nk; i++ {
    86  		mk[i] = binary.BigEndian.Uint32(key[4*i:])
    87  		k[i] = mk[i] ^ fk[i]
    88  	}
    89  
    90  	for i = 0; i < rounds; i++ {
    91  		// 合成置换再异或
    92  		k[i+4] = k[i] ^ t2(k[i+1]^k[i+2]^k[i+3]^ck[i])
    93  		enc[i] = k[i+4]
    94  	}
    95  
    96  	// Derive decryption key from encryption key.
    97  	if dec == nil {
    98  		return
    99  	}
   100  	for i = 0; i < rounds; i++ {
   101  		dec[i] = enc[rounds-1-i]
   102  	}
   103  }
   104  
   105  // sm4块解密
   106  //
   107  //	外部调用时需保证xk是逆序的轮密钥
   108  //	Decrypt one block from src into dst, using the expanded key xk.
   109  func decryptBlockGo(xk []uint32, dst, src []byte) {
   110  	encryptBlockGo(xk, dst, src)
   111  }
   112  
   113  // 轮函数用线性变换函数
   114  //
   115  //	L(B)
   116  func l(b uint32) uint32 {
   117  	return b ^ bits.RotateLeft32(b, 2) ^ bits.RotateLeft32(b, 10) ^ bits.RotateLeft32(b, 18) ^ bits.RotateLeft32(b, 24)
   118  }
   119  
   120  // 密钥扩展用线性变换函数
   121  //
   122  //	L'(B)
   123  func l2(b uint32) uint32 {
   124  	return b ^ bits.RotateLeft32(b, 13) ^ bits.RotateLeft32(b, 23)
   125  }
   126  
   127  // 合成置换函数
   128  func _t(in uint32, fn convert) uint32 {
   129  	var bytes [4]byte
   130  	binary.BigEndian.PutUint32(bytes[:], in)
   131  	// 使用s盒映射实现非线性变换
   132  	for i := 0; i < 4; i++ {
   133  		bytes[i] = sbox[bytes[i]]
   134  	}
   135  	// 调用线性变换函数
   136  	return fn(binary.BigEndian.Uint32(bytes[:]))
   137  }
   138  
   139  // 轮函数用合成置换函数
   140  //
   141  //	T
   142  func t(in uint32) uint32 {
   143  	return _t(in, l)
   144  }
   145  
   146  // 密钥扩展用合成置换函数
   147  //
   148  //	T'
   149  func t2(in uint32) uint32 {
   150  	return _t(in, l2)
   151  }
   152  
   153  // 优化的轮函数用合成置换函数
   154  //
   155  //	5~28轮使用
   156  func precomputeT(in uint32) uint32 {
   157  	return sboxT0[byte(in>>24)] ^
   158  		sboxT1[byte(in>>16)] ^
   159  		sboxT2[byte(in>>8)] ^
   160  		sboxT3[byte(in)]
   161  }