gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/sm3/sm3.go (about) 1 // Package sm3 handle shangmi sm3 hash algorithm 2 package sm3 3 4 /* 5 sm3/sm3.go SM3实现 6 [GM/T] SM3 GB/T 32905-2016 7 */ 8 9 import ( 10 "encoding/binary" 11 "errors" 12 "hash" 13 ) 14 15 // Size SM3校验和字节数,即散列结果的字节长度 16 const Size int = 32 17 18 // BlockSize SM3散列块字节数 19 const BlockSize int = 64 20 21 // 编译运行本模块代码的平台的CPU架构 22 var cpuType = "unknown" 23 24 const ( 25 chunk = 64 26 init0 = 0x7380166f 27 init1 = 0x4914b2b9 28 init2 = 0x172442d7 29 init3 = 0xda8a0600 30 init4 = 0xa96f30bc 31 init5 = 0x163138aa 32 init6 = 0xe38dee4d 33 init7 = 0xb0fb0e4e 34 ) 35 36 // 摘要digest结构体,是对校验和的部分描述 37 type digest struct { 38 h [8]uint32 39 x [chunk]byte 40 nx int 41 len uint64 42 } 43 44 const ( 45 magic256 = "sm3\x03" 46 marshaledSize = len(magic256) + 8*4 + chunk + 8 47 ) 48 49 // MarshalBinary 将摘要digest序列化为字节数组 50 func (d *digest) MarshalBinary() ([]byte, error) { 51 b := make([]byte, 0, marshaledSize) 52 b = append(b, magic256...) 53 b = appendUint32(b, d.h[0]) 54 b = appendUint32(b, d.h[1]) 55 b = appendUint32(b, d.h[2]) 56 b = appendUint32(b, d.h[3]) 57 b = appendUint32(b, d.h[4]) 58 b = appendUint32(b, d.h[5]) 59 b = appendUint32(b, d.h[6]) 60 b = appendUint32(b, d.h[7]) 61 b = append(b, d.x[:d.nx]...) 62 b = b[:len(b)+len(d.x)-d.nx] // already zero 63 b = appendUint64(b, d.len) 64 return b, nil 65 } 66 67 // UnmarshalBinary 将字节数组反序列化为摘要digest 68 func (d *digest) UnmarshalBinary(b []byte) error { 69 if len(b) < len(magic256) || (string(b[:len(magic256)]) != magic256) { 70 return errors.New("sm3: invalid hash state identifier") 71 } 72 if len(b) != marshaledSize { 73 return errors.New("sm3: invalid hash state size") 74 } 75 b = b[len(magic256):] 76 b, d.h[0] = consumeUint32(b) 77 b, d.h[1] = consumeUint32(b) 78 b, d.h[2] = consumeUint32(b) 79 b, d.h[3] = consumeUint32(b) 80 b, d.h[4] = consumeUint32(b) 81 b, d.h[5] = consumeUint32(b) 82 b, d.h[6] = consumeUint32(b) 83 b, d.h[7] = consumeUint32(b) 84 b = b[copy(d.x[:], b):] 85 b, d.len = consumeUint64(b) 86 d.nx = int(d.len % chunk) 87 return nil 88 } 89 90 func appendUint64(b []byte, x uint64) []byte { 91 var a [8]byte 92 binary.BigEndian.PutUint64(a[:], x) 93 return append(b, a[:]...) 94 } 95 96 func appendUint32(b []byte, x uint32) []byte { 97 var a [4]byte 98 binary.BigEndian.PutUint32(a[:], x) 99 return append(b, a[:]...) 100 } 101 102 func consumeUint64(b []byte) ([]byte, uint64) { 103 _ = b[7] 104 x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | 105 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 106 return b[8:], x 107 } 108 109 func consumeUint32(b []byte) ([]byte, uint32) { 110 _ = b[3] 111 x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 112 return b[4:], x 113 } 114 115 // New 生成一个新的hash.Hash,用来计算SM3校验和。 116 // New returns a new hash.Hash computing the SM3 checksum. The Hash 117 // also implements encoding.BinaryMarshaler and 118 // encoding.BinaryUnmarshaler to marshal and unmarshal the internal 119 // state of the hash. 120 func New() hash.Hash { 121 d := new(digest) 122 d.Reset() 123 return d 124 } 125 126 // Sum 将当前哈希附加到 b 并返回结果切片。 127 // Sum appends the current hash to b and returns the resulting slice. 128 // It does not change the underlying hash state. 129 func (d *digest) Sum(in []byte) []byte { 130 // Make a copy of d so that caller can keep writing and summing. 131 d0 := *d 132 checkSum := d0.checkSum() 133 return append(in, checkSum[:]...) 134 } 135 136 func (d *digest) checkSum() []byte { 137 length := d.len 138 // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. 139 var tmp [64]byte 140 tmp[0] = 0x80 141 if length%64 < 56 { 142 _, err := d.Write(tmp[0 : 56-length%64]) 143 if err != nil { 144 panic(err) 145 } 146 } else { 147 _, err := d.Write(tmp[0 : 64+56-length%64]) 148 if err != nil { 149 panic(err) 150 } 151 } 152 // Length in bits. 153 length <<= 3 154 binary.BigEndian.PutUint64(tmp[:], length) 155 _, err := d.Write(tmp[0:8]) 156 if err != nil { 157 panic(err) 158 } 159 160 if d.nx != 0 { 161 panic("d.nx != 0") 162 } 163 164 var digest [Size]byte 165 166 binary.BigEndian.PutUint32(digest[0:], d.h[0]) 167 binary.BigEndian.PutUint32(digest[4:], d.h[1]) 168 binary.BigEndian.PutUint32(digest[8:], d.h[2]) 169 binary.BigEndian.PutUint32(digest[12:], d.h[3]) 170 binary.BigEndian.PutUint32(digest[16:], d.h[4]) 171 binary.BigEndian.PutUint32(digest[20:], d.h[5]) 172 binary.BigEndian.PutUint32(digest[24:], d.h[6]) 173 binary.BigEndian.PutUint32(digest[28:], d.h[7]) 174 175 return digest[:] 176 } 177 178 func (d *digest) Write(p []byte) (nn int, err error) { 179 nn = len(p) 180 d.len += uint64(nn) 181 if d.nx > 0 { 182 n := copy(d.x[d.nx:], p) 183 d.nx += n 184 if d.nx == chunk { 185 block(d, d.x[:]) 186 d.nx = 0 187 } 188 p = p[n:] 189 } 190 if len(p) >= chunk { 191 n := len(p) &^ (chunk - 1) 192 block(d, p[:n]) 193 p = p[n:] 194 } 195 if len(p) > 0 { 196 d.nx = copy(d.x[:], p) 197 } 198 return 199 } 200 201 func (d *digest) Size() int { 202 return Size 203 } 204 205 func (d *digest) BlockSize() int { return BlockSize } 206 207 // Reset resets the Hash to its initial state. 208 func (d *digest) Reset() { 209 d.h[0] = init0 210 d.h[1] = init1 211 d.h[2] = init2 212 d.h[3] = init3 213 d.h[4] = init4 214 d.h[5] = init5 215 d.h[6] = init6 216 d.h[7] = init7 217 d.nx = 0 218 d.len = 0 219 } 220 221 // Sm3Sum returns the SM3 checksum of the data. 222 //goland:noinspection GoNameStartsWithPackageName 223 func Sm3Sum(data []byte) []byte { 224 var d digest 225 d.Reset() 226 _, err := d.Write(data) 227 if err != nil { 228 panic(err) 229 } 230 return d.checkSum() 231 } 232 233 // Sm3SumArr 计算Sm3散列值,返回长度32的字节数组 234 // @param data 散列对象 235 // @return sumSm3 长度32的字节数组 236 //goland:noinspection GoNameStartsWithPackageName 237 func Sm3SumArr(data []byte) (sumSm3 [Size]byte) { 238 sum := Sm3Sum(data) 239 copy(sumSm3[:], sum[:Size]) 240 return 241 } 242 243 // Sum 计算sm3散列值,返回长度32的字节数组 244 // @param data 散列对象 245 // @return [Size]byte 长度32的字节数组 246 //goland:noinspection GoUnusedExportedFunction 247 func Sum(data []byte) [Size]byte { 248 return Sm3SumArr(data) 249 }