mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 12:52:28 +08:00
* feat: add ContainAny * feat:encryption adds support for SM2, SM3, and SM4 #131 * doc: add docment for SM2, SM3, and SM4 #131 --------- Co-authored-by: Jiawen <im@linjiawen.com>
212 lines
3.6 KiB
Go
212 lines
3.6 KiB
Go
package cryptor
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"hash"
|
|
)
|
|
|
|
// SM3 implements the Chinese SM3 cryptographic hash algorithm.
|
|
// SM3 produces a 256-bit (32-byte) hash value.
|
|
|
|
const (
|
|
sm3BlockSize = 64
|
|
sm3Size = 32
|
|
sm3T1 = 0x79cc4519
|
|
sm3T2 = 0x7a879d8a
|
|
)
|
|
|
|
var sm3IV = [8]uint32{
|
|
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
|
|
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e,
|
|
}
|
|
|
|
type sm3Digest struct {
|
|
h [8]uint32
|
|
x [sm3BlockSize]byte
|
|
nx int
|
|
len uint64
|
|
}
|
|
|
|
// Sm3 returns a new hash.Hash computing the SM3 checksum.
|
|
// Play: https://go.dev/play/p/zDAQpteAiOc
|
|
func Sm3(data []byte) []byte {
|
|
h := newSm3()
|
|
h.Write(data)
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
func newSm3() hash.Hash {
|
|
d := new(sm3Digest)
|
|
d.Reset()
|
|
return d
|
|
}
|
|
|
|
func (d *sm3Digest) Reset() {
|
|
d.h = sm3IV
|
|
d.nx = 0
|
|
d.len = 0
|
|
}
|
|
|
|
func (d *sm3Digest) Size() int {
|
|
return sm3Size
|
|
}
|
|
|
|
func (d *sm3Digest) BlockSize() int {
|
|
return sm3BlockSize
|
|
}
|
|
|
|
func (d *sm3Digest) Write(p []byte) (nn int, err error) {
|
|
nn = len(p)
|
|
d.len += uint64(nn)
|
|
|
|
if d.nx > 0 {
|
|
n := copy(d.x[d.nx:], p)
|
|
d.nx += n
|
|
if d.nx == sm3BlockSize {
|
|
sm3Block(d, d.x[:])
|
|
d.nx = 0
|
|
}
|
|
p = p[n:]
|
|
}
|
|
|
|
if len(p) >= sm3BlockSize {
|
|
n := len(p) &^ (sm3BlockSize - 1)
|
|
sm3Block(d, p[:n])
|
|
p = p[n:]
|
|
}
|
|
|
|
if len(p) > 0 {
|
|
d.nx = copy(d.x[:], p)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (d *sm3Digest) Sum(in []byte) []byte {
|
|
d0 := *d
|
|
hash := d0.checkSum()
|
|
return append(in, hash[:]...)
|
|
}
|
|
|
|
func (d *sm3Digest) checkSum() [sm3Size]byte {
|
|
len := d.len
|
|
var tmp [64]byte
|
|
tmp[0] = 0x80
|
|
|
|
if len%64 < 56 {
|
|
d.Write(tmp[0 : 56-len%64])
|
|
} else {
|
|
d.Write(tmp[0 : 64+56-len%64])
|
|
}
|
|
|
|
len <<= 3
|
|
binary.BigEndian.PutUint64(tmp[:], len)
|
|
d.Write(tmp[0:8])
|
|
|
|
if d.nx != 0 {
|
|
panic("d.nx != 0")
|
|
}
|
|
|
|
var digest [sm3Size]byte
|
|
for i := 0; i < 8; i++ {
|
|
binary.BigEndian.PutUint32(digest[i*4:], d.h[i])
|
|
}
|
|
|
|
return digest
|
|
}
|
|
|
|
func sm3Block(dig *sm3Digest, p []byte) {
|
|
var w [68]uint32
|
|
var w1 [64]uint32
|
|
|
|
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
|
|
|
|
for len(p) >= sm3BlockSize {
|
|
for i := 0; i < 16; i++ {
|
|
j := i * 4
|
|
w[i] = binary.BigEndian.Uint32(p[j : j+4])
|
|
}
|
|
|
|
for i := 16; i < 68; i++ {
|
|
w[i] = sm3P1(w[i-16]^w[i-9]^sm3RotateLeft(w[i-3], 15)) ^ sm3RotateLeft(w[i-13], 7) ^ w[i-6]
|
|
}
|
|
|
|
for i := 0; i < 64; i++ {
|
|
w1[i] = w[i] ^ w[i+4]
|
|
}
|
|
|
|
A, B, C, D, E, F, G, H := h0, h1, h2, h3, h4, h5, h6, h7
|
|
|
|
for j := 0; j < 64; j++ {
|
|
var ss1, ss2, tt1, tt2, t uint32
|
|
|
|
if j < 16 {
|
|
t = sm3T1
|
|
} else {
|
|
t = sm3T2
|
|
}
|
|
|
|
ss1 = sm3RotateLeft(sm3RotateLeft(A, 12)+E+sm3RotateLeft(t, uint32(j%32)), 7)
|
|
ss2 = ss1 ^ sm3RotateLeft(A, 12)
|
|
|
|
if j < 16 {
|
|
tt1 = sm3FF0(A, B, C) + D + ss2 + w1[j]
|
|
tt2 = sm3GG0(E, F, G) + H + ss1 + w[j]
|
|
} else {
|
|
tt1 = sm3FF1(A, B, C) + D + ss2 + w1[j]
|
|
tt2 = sm3GG1(E, F, G) + H + ss1 + w[j]
|
|
}
|
|
|
|
D = C
|
|
C = sm3RotateLeft(B, 9)
|
|
B = A
|
|
A = tt1
|
|
H = G
|
|
G = sm3RotateLeft(F, 19)
|
|
F = E
|
|
E = sm3P0(tt2)
|
|
}
|
|
|
|
h0 ^= A
|
|
h1 ^= B
|
|
h2 ^= C
|
|
h3 ^= D
|
|
h4 ^= E
|
|
h5 ^= F
|
|
h6 ^= G
|
|
h7 ^= H
|
|
|
|
p = p[sm3BlockSize:]
|
|
}
|
|
|
|
dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
|
|
}
|
|
|
|
func sm3RotateLeft(x, n uint32) uint32 {
|
|
return (x << n) | (x >> (32 - n))
|
|
}
|
|
|
|
func sm3P0(x uint32) uint32 {
|
|
return x ^ sm3RotateLeft(x, 9) ^ sm3RotateLeft(x, 17)
|
|
}
|
|
|
|
func sm3P1(x uint32) uint32 {
|
|
return x ^ sm3RotateLeft(x, 15) ^ sm3RotateLeft(x, 23)
|
|
}
|
|
|
|
func sm3FF0(x, y, z uint32) uint32 {
|
|
return x ^ y ^ z
|
|
}
|
|
|
|
func sm3FF1(x, y, z uint32) uint32 {
|
|
return (x & y) | (x & z) | (y & z)
|
|
}
|
|
|
|
func sm3GG0(x, y, z uint32) uint32 {
|
|
return x ^ y ^ z
|
|
}
|
|
|
|
func sm3GG1(x, y, z uint32) uint32 {
|
|
return (x & y) | (^x & z)
|
|
}
|