gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/sm4soft/sm4_gcm.go (about) 1 // Copyright (c) 2022 zhaochun 2 // core-gm is licensed under Mulan PSL v2. 3 // You can use this software according to the terms and conditions of the Mulan PSL v2. 4 // You may obtain a copy of Mulan PSL v2 at: 5 // http://license.coscl.org.cn/MulanPSL2 6 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 7 // See the Mulan PSL v2 for more details. 8 9 /* 10 sm4soft 是sm4的纯软实现,基于tjfoc国密算法库`tjfoc/gmsm`做了少量修改。 11 对应版权声明: thrid_licenses/github.com/tjfoc/gmsm/版权声明 12 */ 13 14 package sm4soft 15 16 import ( 17 "errors" 18 "strconv" 19 ) 20 21 // Sm4GCM SM4 GCM 加解密模式 22 // Paper: The Galois/Counter Mode of Operation (GCM) David A. Mcgrew,John Viega .2004. 23 // key: 对称加密密钥 24 // IV: IV向量 25 // in: 26 // A: 附加的可鉴别数据(ADD) 27 // mode: true - 加密; false - 解密验证 28 // 29 // return: 密文C, 鉴别标签T, 错误 30 func Sm4GCM(key []byte, IV, in, A []byte, mode bool) ([]byte, []byte, error) { 31 if len(key) != BlockSize { 32 return nil, nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key))) 33 } 34 if mode { 35 C, T := GCMEncrypt(key, IV, in, A) 36 return C, T, nil 37 } else { 38 P, _T := GCMDecrypt(key, IV, in, A) 39 return P, _T, nil 40 } 41 } 42 43 // GetH 对“0”分组的加密得到 GHASH泛杂凑函数的子密钥 44 // key: 对称密钥 45 // return: GHASH泛杂凑函数的子密钥 46 func GetH(key []byte) (H []byte) { 47 c, err := NewCipher(key) 48 if err != nil { 49 panic(err) 50 } 51 52 zores := make([]byte, BlockSize) 53 H = make([]byte, BlockSize) 54 c.Encrypt(H, zores) 55 return H 56 } 57 58 // ut = a + b 59 func addition(a, b []byte) (out []byte) { 60 Len := len(a) 61 if Len != len(b) { 62 return nil 63 } 64 out = make([]byte, Len) 65 for i := 0; i < Len; i++ { 66 out[i] = a[i] ^ b[i] 67 } 68 return out 69 } 70 71 func Rightshift(V []byte) { 72 n := len(V) 73 for i := n - 1; i >= 0; i-- { 74 V[i] = V[i] >> 1 75 if i != 0 { 76 V[i] = ((V[i-1] & 0x01) << 7) | V[i] 77 } 78 } 79 } 80 81 func findYi(Y []byte, index int) int { 82 var temp byte 83 i := uint(index) 84 temp = Y[i/8] 85 temp = temp >> (7 - i%8) 86 if temp&0x01 == 1 { 87 return 1 88 } else { 89 return 0 90 } 91 } 92 93 func multiplication(X, Y []byte) (Z []byte) { 94 95 R := make([]byte, BlockSize) 96 R[0] = 0xe1 97 Z = make([]byte, BlockSize) 98 V := make([]byte, BlockSize) 99 copy(V, X) 100 for i := 0; i <= 127; i++ { 101 if findYi(Y, i) == 1 { 102 Z = addition(Z, V) 103 } 104 if V[BlockSize-1]&0x01 == 0 { 105 Rightshift(V) 106 } else { 107 Rightshift(V) 108 V = addition(V, R) 109 } 110 } 111 return Z 112 } 113 114 func GHASH(H []byte, A []byte, C []byte) (X []byte) { 115 116 calculmV := func(m, v int) (int, int) { 117 if m == 0 && v != 0 { 118 m = 1 119 v = v * 8 120 } else if m != 0 && v == 0 { 121 v = BlockSize * 8 122 } else if m != 0 && v != 0 { 123 m = m + 1 124 v = v * 8 125 } else { //m==0 && v==0 126 m = 1 127 v = 0 128 } 129 return m, v 130 } 131 m := len(A) / BlockSize 132 v := len(A) % BlockSize 133 m, v = calculmV(m, v) 134 135 n := len(C) / BlockSize 136 u := len(C) % BlockSize 137 n, u = calculmV(n, u) 138 139 //i=0 140 X = make([]byte, BlockSize*(m+n+2)) //X0 = 0 141 for i := 0; i < BlockSize; i++ { 142 X[i] = 0x00 143 } 144 145 //i=1...m-1 146 for i := 1; i <= m-1; i++ { 147 copy(X[i*BlockSize:i*BlockSize+BlockSize], multiplication(addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], A[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize]), H)) //A 1-->m-1 对于数组来说是 0-->m-2 148 } 149 150 //i=m 151 zeros := make([]byte, (128-v)/8) 152 Am := make([]byte, v/8) 153 copy(Am[:], A[(m-1)*BlockSize:]) 154 Am = append(Am, zeros...) 155 copy(X[m*BlockSize:m*BlockSize+BlockSize], multiplication(addition(X[(m-1)*BlockSize:(m-1)*BlockSize+BlockSize], Am), H)) 156 157 //i=m+1...m+n-1 158 for i := m + 1; i <= (m + n - 1); i++ { 159 copy(X[i*BlockSize:i*BlockSize+BlockSize], multiplication(addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], C[(i-m-1)*BlockSize:(i-m-1)*BlockSize+BlockSize]), H)) 160 } 161 162 //i=m+n 163 zeros = make([]byte, (128-u)/8) 164 Cn := make([]byte, u/8) 165 copy(Cn[:], C[(n-1)*BlockSize:]) 166 Cn = append(Cn, zeros...) 167 copy(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], multiplication(addition(X[(m+n-1)*BlockSize:(m+n-1)*BlockSize+BlockSize], Cn), H)) 168 169 //i=m+n+1 170 var lenAB []byte 171 calculateLenToBytes := func(len int) []byte { 172 data := make([]byte, 8) 173 data[0] = byte((len >> 56) & 0xff) 174 data[1] = byte((len >> 48) & 0xff) 175 data[2] = byte((len >> 40) & 0xff) 176 data[3] = byte((len >> 32) & 0xff) 177 data[4] = byte((len >> 24) & 0xff) 178 data[5] = byte((len >> 16) & 0xff) 179 data[6] = byte((len >> 8) & 0xff) 180 data[7] = byte((len >> 0) & 0xff) 181 return data 182 } 183 lenAB = append(lenAB, calculateLenToBytes(len(A))...) 184 lenAB = append(lenAB, calculateLenToBytes(len(C))...) 185 copy(X[(m+n+1)*BlockSize:(m+n+1)*BlockSize+BlockSize], multiplication(addition(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], lenAB), H)) 186 return X[(m+n+1)*BlockSize : (m+n+1)*BlockSize+BlockSize] 187 } 188 189 // GetY0 生成初始的计数器时钟J0 190 // 191 // H: GHASH自密钥 192 // IV: IV向量 193 // return: 初始的计数器时钟(J0) 194 func GetY0(H, IV []byte) []byte { 195 if len(IV)*8 == 96 { 196 zero31one1 := []byte{0x00, 0x00, 0x00, 0x01} 197 IV = append(IV, zero31one1...) 198 return IV 199 } else { 200 return GHASH(H, []byte{}, IV) 201 } 202 } 203 204 func incr(n int, YI []byte) (YIi []byte) { 205 206 YIi = make([]byte, BlockSize*n) 207 copy(YIi, YI) 208 209 addYone := func(yi, yii []byte) { 210 copy(yii[:], yi[:]) 211 212 Len := len(yi) 213 var rc byte = 0x00 214 for i := Len - 1; i >= 0; i-- { 215 if i == Len-1 { 216 if yii[i] < 0xff { 217 yii[i] = yii[i] + 0x01 218 rc = 0x00 219 } else { 220 yii[i] = 0x00 221 rc = 0x01 222 } 223 } else { 224 if yii[i]+rc < 0xff { 225 yii[i] = yii[i] + rc 226 rc = 0x00 227 } else { 228 yii[i] = 0x00 229 rc = 0x01 230 } 231 } 232 } 233 } 234 for i := 1; i < n; i++ { //2^32 235 addYone(YIi[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], YIi[i*BlockSize:i*BlockSize+BlockSize]) 236 } 237 return YIi 238 } 239 240 func MSB(len int, S []byte) (out []byte) { 241 return S[:len/8] 242 } 243 244 // GCMEncrypt 可鉴别加密函数 (GCM-AE(k)) 245 // K: 对称密钥 246 // IV: IV向量 247 // P: 明文 248 // A: 附加的鉴别数据 249 // 250 // return: 密文, 鉴别标签 251 func GCMEncrypt(K, IV, P, A []byte) (C, T []byte) { 252 calculmV := func(m, v int) (int, int) { 253 if m == 0 && v != 0 { 254 m = 1 255 v = v * 8 256 } else if m != 0 && v == 0 { 257 v = BlockSize * 8 258 } else if m != 0 && v != 0 { 259 m = m + 1 260 v = v * 8 261 } else { //m==0 && v==0 262 m = 1 263 v = 0 264 } 265 return m, v 266 } 267 n := len(P) / BlockSize 268 u := len(P) % BlockSize 269 n, u = calculmV(n, u) 270 271 // a) 通过对“0”分组的加密得到 GHASH泛杂凑函数的子密钥 272 H := GetH(K) 273 274 Y0 := GetY0(H, IV) 275 276 // Y := make([]byte, BlockSize*(n+1)) 277 Y := incr(n+1, Y0) 278 c, err := NewCipher(K) 279 if err != nil { 280 panic(err) 281 } 282 Enc := make([]byte, BlockSize) 283 C = make([]byte, len(P)) 284 285 //i=1...n-1 286 for i := 1; i <= n-1; i++ { 287 c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize]) 288 289 copy(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc)) 290 } 291 292 //i=n 293 c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize]) 294 out := MSB(u, Enc) 295 copy(C[(n-1)*BlockSize:], addition(P[(n-1)*BlockSize:], out)) 296 297 c.Encrypt(Enc, Y0) 298 299 t := 128 300 T = MSB(t, addition(Enc, GHASH(H, A, C))) 301 return C, T 302 } 303 304 func GCMDecrypt(K, IV, C, A []byte) (P, _T []byte) { 305 calculmV := func(m, v int) (int, int) { 306 if m == 0 && v != 0 { 307 m = 1 308 v = v * 8 309 } else if m != 0 && v == 0 { 310 v = BlockSize * 8 311 } else if m != 0 && v != 0 { 312 m = m + 1 313 v = v * 8 314 } else { //m==0 && v==0 315 m = 1 316 v = 0 317 } 318 return m, v 319 } 320 321 H := GetH(K) 322 323 Y0 := GetY0(H, IV) 324 325 Enc := make([]byte, BlockSize) 326 c, err := NewCipher(K) 327 if err != nil { 328 panic(err) 329 } 330 c.Encrypt(Enc, Y0) 331 t := 128 332 _T = MSB(t, addition(Enc, GHASH(H, A, C))) 333 334 n := len(C) / BlockSize 335 u := len(C) % BlockSize 336 n, u = calculmV(n, u) 337 // Y := make([]byte, BlockSize*(n+1)) 338 Y := incr(n+1, Y0) 339 340 P = make([]byte, BlockSize*n) 341 for i := 1; i <= n; i++ { 342 c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize]) 343 copy(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc)) 344 } 345 346 c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize]) 347 out := MSB(u, Enc) 348 copy(P[(n-1)*BlockSize:], addition(C[(n-1)*BlockSize:], out)) 349 350 return P, _T 351 }