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  }