Files
2026-05-27 23:03:00 +08:00

208 lines
5.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///
/// Copyright (c) 2018 xdx. All rights reserved.
///
/// \file: block.go
///
/// \brief: sm4 block-function
///
/// \author: xdx
///
package sm4
import (
"encoding/binary"
)
func rotl(x, n uint32) uint32 {
return (x << n) | (x >> (32 - n))
}
/*
* Expanded SM4 S-boxes
* Sbox table: 8bits input convert to 8 bits output
*/
var sbox = [256]byte{
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
}
func tau(x uint32) uint32 {
return uint32(sbox[x&0xff]) |
uint32(sbox[(x>>8)&0xff])<<8 |
uint32(sbox[(x>>16)&0xff])<<16 |
uint32(sbox[(x>>24)&0xff])<<24
}
func l(x uint32) uint32 {
return x ^ rotl(x, 2) ^ rotl(x, 10) ^ rotl(x, 18) ^ rotl(x, 24)
}
// sbox8 分别rotl 8, 16, 24
var sbox8l8, sbox8l16, sbox8l24 [256]uint32
// sbox16 maps a uint16 to uint32
// sbox16(b0||b1) = L(t(b0)) ^ L(t(b1) << 8)
var sbox16 []uint32
// sbox16Rotl = sbox16[i] << 16
var sbox16Rotl []uint32
const useSbox65536 = true
func init() {
if useSbox65536 {
sbox16 = make([]uint32, 65536)
sbox16Rotl = make([]uint32, 65536)
for i := 0; i < 65536; i++ {
x := l(uint32(sbox[i&0xff])) ^ l(uint32(sbox[(i>>8)&0xff])<<8)
sbox16[i] = x
sbox16Rotl[i] = (x >> 16) | (x << 16)
}
}
for i := 0; i < 256; i++ {
sbox8l8[i] = rotl(ltTable8[i], 8)
sbox8l16[i] = rotl(ltTable8[i], 16)
sbox8l24[i] = rotl(ltTable8[i], 24)
}
}
// lt return L(Tau(x))
func lt(x uint32) uint32 {
if useSbox65536 {
// FIXME: 为什么会更慢?(C下更快)
// sbox16 and sbox16Rotl taken 512KB memorys. too big and cache may always missing.
// thus is slower than 1.
return sbox16Rotl[x>>16] ^ sbox16[x&0xffff]
// return ltauTable16[x&0xffff] ^ rotl(ltauTable16[x>>16], 16)
} else {
// 1. 4次右移,4次& 4次查表
return sbox8l24[(x>>24)&0xff] ^ sbox8l16[(x>>16)&0xff] ^ sbox8l8[(x>>8)&0xff] ^ ltTable8[x&0xff]
// 2. 4次右移,4次& 4次rotl 比1略慢
// return rotl(sbox8[(x>>24)&0xff], 24) ^ rotl(sbox8[(x>>16)&0xff], 16) ^ rotl(sbox8[(x>>8)&0xff], 8) ^ sbox8[x&0xff]
// 3. 至少慢一半
// return l(tau(x))
}
}
/*
Encrypt one block
Can asm code be much more faster?
*/
func encryptBlockGo(key []uint32, output, input []byte) {
// var a, b, c, d uint32
a := binary.BigEndian.Uint32(input[:4])
b := binary.BigEndian.Uint32(input[4:8])
c := binary.BigEndian.Uint32(input[8:12])
d := binary.BigEndian.Uint32(input[12:16])
for i := 0; i < 8; i++ {
e := c ^ d
a ^= lt(e ^ b ^ key[4*i+0])
b ^= lt(e ^ a ^ key[4*i+1])
e = a ^ b
c ^= lt(e ^ d ^ key[4*i+2])
d ^= lt(e ^ c ^ key[4*i+3])
}
binary.BigEndian.PutUint32(output[:4], d)
binary.BigEndian.PutUint32(output[4:8], c)
binary.BigEndian.PutUint32(output[8:12], b)
binary.BigEndian.PutUint32(output[12:16], a)
}
/*
Decrypt one block, same as encryption except the key are reversed
*/
func decryptBlockGo(key []uint32, output, input []byte) {
encryptBlockGo(key, output, input)
}
////////////////////////////////////////////////////////////////////
//
// Key schedule
//
////////////////////////////////////////////////////////////////////
/* fixed parameter */
var ck = [32]uint32{
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,
}
var fk = [4]uint32{0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc}
// Key expansion algorithm. See FIPS-197, Figure 11.
// Their rcon[i] is our powx[i-1] << 24.
func expandKeyGo(key []byte, enc, dec []uint32) {
a := binary.BigEndian.Uint32(key[:4]) ^ fk[0]
b := binary.BigEndian.Uint32(key[4:8]) ^ fk[1]
c := binary.BigEndian.Uint32(key[8:12]) ^ fk[2]
d := binary.BigEndian.Uint32(key[12:16]) ^ fk[3]
var t uint32
for i := 0; i < 32; {
t = tau(b ^ c ^ d ^ ck[i])
a ^= t ^ rotl(t, 13) ^ rotl(t, 23)
enc[i] = a
dec[31-i] = a
i++
t = tau(a ^ c ^ d ^ ck[i])
b ^= t ^ rotl(t, 13) ^ rotl(t, 23)
enc[i] = b
dec[31-i] = b
i++
t = tau(a ^ b ^ d ^ ck[i])
c ^= t ^ rotl(t, 13) ^ rotl(t, 23)
enc[i] = c
dec[31-i] = c
i++
t = tau(a ^ c ^ b ^ ck[i])
d ^= t ^ rotl(t, 13) ^ rotl(t, 23)
enc[i] = d
dec[31-i] = d
i++
}
}