356 lines
8.0 KiB
Go
356 lines
8.0 KiB
Go
|
/*
|
|||
|
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. Mcgrew,John 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
|
|||
|
}
|