2021-12-04 16:42:11 +00:00

356 lines
8.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright Hyperledger-TWGC All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
writed by Zhiwei Yan, 2020 Oct
*/
package sm4
import (
"errors"
"strconv"
)
// Sm4GCM SM4 GCM 加解密模式
// Paper: The Galois/Counter Mode of Operation (GCM) David A. McgrewJohn Viega .2004.
// key: 对称加密密钥
// IV: IV向量
// in:
// A: 附加的可鉴别数据(ADD)
// mode: true - 加密; false - 解密验证
//
// return: 密文C, 鉴别标签T, 错误
func Sm4GCM(key []byte, IV, in, A []byte, mode bool) ([]byte, []byte, error) {
if len(key) != BlockSize {
return nil, nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
}
if mode {
C, T := GCMEncrypt(key, IV, in, A)
return C, T, nil
} else {
P, _T := GCMDecrypt(key, IV, in, A)
return P, _T, nil
}
}
// GetH 对“0”分组的加密得到 GHASH泛杂凑函数的子密钥
// key: 对称密钥
// return: GHASH泛杂凑函数的子密钥
func GetH(key []byte) (H []byte) {
c, err := NewCipher(key)
if err != nil {
panic(err)
}
zores := make([]byte, BlockSize)
H = make([]byte, BlockSize)
c.Encrypt(H, zores)
return H
}
//ut = a + b
func addition(a, b []byte) (out []byte) {
Len := len(a)
if Len != len(b) {
return nil
}
out = make([]byte, Len)
for i := 0; i < Len; i++ {
out[i] = a[i] ^ b[i]
}
return out
}
func Rightshift(V []byte) {
n := len(V)
for i := n - 1; i >= 0; i-- {
V[i] = V[i] >> 1
if i != 0 {
V[i] = ((V[i-1] & 0x01) << 7) | V[i]
}
}
}
func findYi(Y []byte, index int) int {
var temp byte
i := uint(index)
temp = Y[i/8]
temp = temp >> (7 - i%8)
if temp&0x01 == 1 {
return 1
} else {
return 0
}
}
func multiplication(X, Y []byte) (Z []byte) {
R := make([]byte, BlockSize)
R[0] = 0xe1
Z = make([]byte, BlockSize)
V := make([]byte, BlockSize)
copy(V, X)
for i := 0; i <= 127; i++ {
if findYi(Y, i) == 1 {
Z = addition(Z, V)
}
if V[BlockSize-1]&0x01 == 0 {
Rightshift(V)
} else {
Rightshift(V)
V = addition(V, R)
}
}
return Z
}
func GHASH(H []byte, A []byte, C []byte) (X []byte) {
calculm_v := func(m, v int) (int, int) {
if m == 0 && v != 0 {
m = 1
v = v * 8
} else if m != 0 && v == 0 {
v = BlockSize * 8
} else if m != 0 && v != 0 {
m = m + 1
v = v * 8
} else { //m==0 && v==0
m = 1
v = 0
}
return m, v
}
m := len(A) / BlockSize
v := len(A) % BlockSize
m, v = calculm_v(m, v)
n := len(C) / BlockSize
u := (len(C) % BlockSize)
n, u = calculm_v(n, u)
//i=0
X = make([]byte, BlockSize*(m+n+2)) //X0 = 0
for i := 0; i < BlockSize; i++ {
X[i] = 0x00
}
//i=1...m-1
for i := 1; i <= m-1; i++ {
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
}
//i=m
zeros := make([]byte, (128-v)/8)
Am := make([]byte, v/8)
copy(Am[:], A[(m-1)*BlockSize:])
Am = append(Am, zeros...)
copy(X[m*BlockSize:m*BlockSize+BlockSize], multiplication(addition(X[(m-1)*BlockSize:(m-1)*BlockSize+BlockSize], Am), H))
//i=m+1...m+n-1
for i := m + 1; i <= (m + n - 1); i++ {
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))
}
//i=m+n
zeros = make([]byte, (128-u)/8)
Cn := make([]byte, u/8)
copy(Cn[:], C[(n-1)*BlockSize:])
Cn = append(Cn, zeros...)
copy(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], multiplication(addition(X[(m+n-1)*BlockSize:(m+n-1)*BlockSize+BlockSize], Cn), H))
//i=m+n+1
var lenAB []byte
calculateLenToBytes := func(len int) []byte {
data := make([]byte, 8)
data[0] = byte((len >> 56) & 0xff)
data[1] = byte((len >> 48) & 0xff)
data[2] = byte((len >> 40) & 0xff)
data[3] = byte((len >> 32) & 0xff)
data[4] = byte((len >> 24) & 0xff)
data[5] = byte((len >> 16) & 0xff)
data[6] = byte((len >> 8) & 0xff)
data[7] = byte((len >> 0) & 0xff)
return data
}
lenAB = append(lenAB, calculateLenToBytes(len(A))...)
lenAB = append(lenAB, calculateLenToBytes(len(C))...)
copy(X[(m+n+1)*BlockSize:(m+n+1)*BlockSize+BlockSize], multiplication(addition(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize], lenAB), H))
return X[(m+n+1)*BlockSize : (m+n+1)*BlockSize+BlockSize]
}
// GetY0 生成初始的计数器时钟J0
//
// H: GHASH自密钥
// IV: IV向量
// return: 初始的计数器时钟(J0)
func GetY0(H, IV []byte) []byte {
if len(IV)*8 == 96 {
zero31one1 := []byte{0x00, 0x00, 0x00, 0x01}
IV = append(IV, zero31one1...)
return IV
} else {
return GHASH(H, []byte{}, IV)
}
}
func incr(n int, Y_i []byte) (Y_ii []byte) {
Y_ii = make([]byte, BlockSize*n)
copy(Y_ii, Y_i)
addYone := func(yi, yii []byte) {
copy(yii[:], yi[:])
Len := len(yi)
var rc byte = 0x00
for i := Len - 1; i >= 0; i-- {
if i == Len-1 {
if yii[i] < 0xff {
yii[i] = yii[i] + 0x01
rc = 0x00
} else {
yii[i] = 0x00
rc = 0x01
}
} else {
if yii[i]+rc < 0xff {
yii[i] = yii[i] + rc
rc = 0x00
} else {
yii[i] = 0x00
rc = 0x01
}
}
}
}
for i := 1; i < n; i++ { //2^32
addYone(Y_ii[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Y_ii[i*BlockSize:i*BlockSize+BlockSize])
}
return Y_ii
}
func MSB(len int, S []byte) (out []byte) {
return S[:len/8]
}
// GCMEncrypt 可鉴别加密函数 (GCM-AE(k))
// K: 对称密钥
// IV: IV向量
// P: 明文
// A: 附加的鉴别数据
//
// return: 密文, 鉴别标签
func GCMEncrypt(K, IV, P, A []byte) (C, T []byte) {
calculm_v := func(m, v int) (int, int) {
if m == 0 && v != 0 {
m = 1
v = v * 8
} else if m != 0 && v == 0 {
v = BlockSize * 8
} else if m != 0 && v != 0 {
m = m + 1
v = v * 8
} else { //m==0 && v==0
m = 1
v = 0
}
return m, v
}
n := len(P) / BlockSize
u := len(P) % BlockSize
n, u = calculm_v(n, u)
// a) 通过对“0”分组的加密得到 GHASH泛杂凑函数的子密钥
H := GetH(K)
Y0 := GetY0(H, IV)
Y := make([]byte, BlockSize*(n+1))
Y = incr(n+1, Y0)
c, err := NewCipher(K)
if err != nil {
panic(err)
}
Enc := make([]byte, BlockSize)
C = make([]byte, len(P))
//i=1...n-1
for i := 1; i <= n-1; i++ {
c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize])
copy(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc))
}
//i=n
c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize])
out := MSB(u, Enc)
copy(C[(n-1)*BlockSize:], addition(P[(n-1)*BlockSize:], out))
c.Encrypt(Enc, Y0)
t := 128
T = MSB(t, addition(Enc, GHASH(H, A, C)))
return C, T
}
func GCMDecrypt(K, IV, C, A []byte) (P, _T []byte) {
calculm_v := func(m, v int) (int, int) {
if m == 0 && v != 0 {
m = 1
v = v * 8
} else if m != 0 && v == 0 {
v = BlockSize * 8
} else if m != 0 && v != 0 {
m = m + 1
v = v * 8
} else { //m==0 && v==0
m = 1
v = 0
}
return m, v
}
H := GetH(K)
Y0 := GetY0(H, IV)
Enc := make([]byte, BlockSize)
c, err := NewCipher(K)
if err != nil {
panic(err)
}
c.Encrypt(Enc, Y0)
t := 128
_T = MSB(t, addition(Enc, GHASH(H, A, C)))
n := len(C) / BlockSize
u := len(C) % BlockSize
n, u = calculm_v(n, u)
Y := make([]byte, BlockSize*(n+1))
Y = incr(n+1, Y0)
P = make([]byte, BlockSize*n)
for i := 1; i <= n; i++ {
c.Encrypt(Enc, Y[i*BlockSize:i*BlockSize+BlockSize])
copy(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], addition(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize], Enc))
}
c.Encrypt(Enc, Y[n*BlockSize:n*BlockSize+BlockSize])
out := MSB(u, Enc)
copy(P[(n-1)*BlockSize:], addition(C[(n-1)*BlockSize:], out))
return P, _T
}