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