xs/vendor/github.com/tjfoc/gmsm/sm4/sm4_gcm.go

333 lines
6.7 KiB
Go
Raw 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"
)
//Paper: The Galois/Counter Mode of Operation (GCM) David A. McgrewJohn Viega .2004.
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
}
}
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]
}
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]
}
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)
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
}