mirror of https://gogs.blitter.com/RLabs/xs
334 lines
6.7 KiB
Go
334 lines
6.7 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"
|
||
)
|
||
|
||
//Paper: The Galois/Counter Mode of Operation (GCM) David A. Mcgrew,John 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
|
||
}
|