github.com/emmansun/gmsm@v0.29.1/zuc/eia256.go (about) 1 package zuc 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 type ZUC256Mac struct { 9 zucState32 10 k0 [8]uint32 11 t []uint32 12 x [chunk]byte 13 nx int 14 len uint64 15 tagSize int 16 initState zucState32 17 } 18 19 // NewHash256 create hash for zuc-256 eia, with arguments key, iv and tagSize. 20 // Key size is 32 in bytes, iv size is 23 in bytes, tagSize supports 4/8/16 in bytes. 21 // The larger the tag size, the worse the performance. 22 func NewHash256(key, iv []byte, tagSize int) (*ZUC256Mac, error) { 23 k := len(key) 24 ivLen := len(iv) 25 mac := &ZUC256Mac{} 26 var d []byte 27 switch tagSize { 28 default: 29 return nil, fmt.Errorf("zuc: invalid tag size %d, support 4/8/16 in bytes", tagSize) 30 case 4: 31 d = zuc256_d[0][:] 32 case 8: 33 d = zuc256_d[1][:] 34 case 16: 35 d = zuc256_d[2][:] 36 } 37 mac.tagSize = tagSize 38 mac.t = make([]uint32, mac.tagSize/4) 39 switch k { 40 default: 41 return nil, fmt.Errorf("zuc: invalid key size %d, expect 32 in bytes", k) 42 case 32: // ZUC-256 43 if ivLen != IVSize256 { 44 return nil, fmt.Errorf("zuc: invalid iv size %d, expect %d in bytes", ivLen, IVSize256) 45 } 46 mac.loadKeyIV32(key, iv, d) 47 } 48 // initialization 49 for i := 0; i < 32; i++ { 50 mac.bitReorganization() 51 w := mac.f32() 52 mac.enterInitMode(w >> 1) 53 } 54 55 // work state 56 mac.bitReorganization() 57 mac.f32() 58 mac.enterWorkMode() 59 60 mac.initState.r1 = mac.r1 61 mac.initState.r2 = mac.r2 62 63 copy(mac.initState.lfsr[:], mac.lfsr[:]) 64 mac.Reset() 65 return mac, nil 66 } 67 68 func (m *ZUC256Mac) Size() int { 69 return m.tagSize 70 } 71 72 func (m *ZUC256Mac) BlockSize() int { 73 return chunk 74 } 75 76 // Reset resets the Hash to its initial state. 77 func (m *ZUC256Mac) Reset() { 78 m.nx = 0 79 m.len = 0 80 m.r1 = m.initState.r1 81 m.r2 = m.initState.r2 82 copy(m.lfsr[:], m.initState.lfsr[:]) 83 m.genKeywords(m.t) 84 m.genKeywords(m.k0[:4]) 85 } 86 87 func block256Generic(m *ZUC256Mac, p []byte) { 88 var k64, t64 uint64 89 if m.tagSize == 4 { 90 t64 = uint64(m.t[0]) << 32 91 } 92 tagWords := m.tagSize / 4 93 for len(p) >= chunk { 94 m.genKeywords(m.k0[4:]) 95 for l := 0; l < 4; l++ { 96 w := binary.BigEndian.Uint32(p[l*4:]) 97 switch m.tagSize { 98 case 4: 99 k64 = uint64(m.k0[l])<<32 | uint64(m.k0[l+1]) 100 for j := 0; j < 32; j++ { 101 t64 ^= ^(uint64(w>>31) - 1) & k64 102 w <<= 1 103 k64 <<= 1 104 } 105 default: 106 k1 := m.k0[tagWords+l] 107 for i := 0; i < 32; i++ { 108 wBit := ^(w>>31 - 1) 109 for j := 0; j < tagWords; j++ { 110 m.t[j] ^= wBit & m.k0[j] 111 } 112 w <<= 1 113 var j int 114 for j = 0; j < tagWords-1; j++ { 115 m.k0[j] = (m.k0[j] << 1) | (m.k0[j+1] >> 31) 116 } 117 m.k0[j] = (m.k0[j] << 1) | (k1 >> 31) 118 k1 <<= 1 119 } 120 } 121 } 122 if tagWords != 4 { 123 copy(m.k0[:4], m.k0[4:]) 124 } 125 p = p[chunk:] 126 } 127 if m.tagSize == 4 { 128 m.t[0] = uint32(t64 >> 32) 129 } 130 } 131 132 func (m *ZUC256Mac) Write(p []byte) (nn int, err error) { 133 nn = len(p) 134 m.len += uint64(nn) 135 if m.nx > 0 { 136 n := copy(m.x[m.nx:], p) 137 m.nx += n 138 if m.nx == chunk { 139 block256(m, m.x[:]) 140 m.nx = 0 141 } 142 p = p[n:] 143 } 144 if len(p) >= chunk { 145 n := len(p) &^ (chunk - 1) 146 block256(m, p[:n]) 147 p = p[n:] 148 } 149 if len(p) > 0 { 150 m.nx = copy(m.x[:], p) 151 } 152 return 153 } 154 155 func (m *ZUC256Mac) checkSum(additionalBits int, b byte) []byte { 156 if m.nx >= chunk { 157 panic("m.nx >= 16") 158 } 159 kIdx := 0 160 if m.nx > 0 || additionalBits > 0 { 161 m.x[m.nx] = b 162 m.genKeywords(m.k0[4:]) 163 nRemainBits := 8*m.nx + additionalBits 164 words := (nRemainBits + 31) / 32 165 166 for l := 0; l < words-1; l++ { 167 w := binary.BigEndian.Uint32(m.x[l*4:]) 168 k1 := m.k0[m.tagSize/4+l] 169 for i := 0; i < 32; i++ { 170 wBit := ^(w>>31 - 1) 171 for j := 0; j < m.tagSize/4; j++ { 172 m.t[j] ^= wBit & m.k0[j] 173 } 174 w <<= 1 175 var j int 176 for j = 0; j < m.tagSize/4-1; j++ { 177 m.k0[j] = (m.k0[j] << 1) | (m.k0[j+1] >> 31) 178 } 179 m.k0[j] = (m.k0[j] << 1) | (k1 >> 31) 180 k1 <<= 1 181 } 182 } 183 nRemainBits -= (words - 1) * 32 184 kIdx = words - 1 185 if nRemainBits > 0 { 186 w := binary.BigEndian.Uint32(m.x[(words-1)*4:]) 187 for i := 0; i < nRemainBits; i++ { 188 wBit := ^(w>>31 - 1) 189 for j := 0; j < m.tagSize/4; j++ { 190 m.t[j] ^= wBit & m.k0[j+kIdx] 191 } 192 w <<= 1 193 var j int 194 for j = 0; j < m.tagSize/4; j++ { 195 m.k0[j+kIdx] = (m.k0[j+kIdx] << 1) | (m.k0[kIdx+j+1] >> 31) 196 } 197 m.k0[j+kIdx] <<= 1 198 } 199 } 200 } 201 202 digest := make([]byte, m.tagSize) 203 for j := 0; j < m.tagSize/4; j++ { 204 m.t[j] ^= m.k0[j+kIdx] 205 binary.BigEndian.PutUint32(digest[j*4:], m.t[j]) 206 } 207 208 return digest 209 } 210 211 // Finish this function hash nbits data in p and return mac value 212 // In general, we will use byte level function, this is just for test/verify. 213 func (m *ZUC256Mac) Finish(p []byte, nbits int) []byte { 214 if len(p) < (nbits+7)/8 { 215 panic("invalid p length") 216 } 217 nbytes := nbits / 8 218 nRemainBits := nbits - nbytes*8 219 if nbytes > 0 { 220 m.Write(p[:nbytes]) 221 } 222 var b byte 223 if nRemainBits > 0 { 224 b = p[nbytes] 225 } 226 digest := m.checkSum(nRemainBits, b) 227 m.Reset() 228 return digest[:] 229 } 230 231 // Sum appends the current hash to in and returns the resulting slice. 232 // It does not change the underlying hash state. 233 func (m *ZUC256Mac) Sum(in []byte) []byte { 234 // Make a copy of d so that caller can keep writing and summing. 235 d0 := *m 236 d0.t = make([]uint32, len(m.t)) 237 copy(d0.t, m.t) 238 hash := d0.checkSum(0, 0) 239 return append(in, hash[:]...) 240 }