| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /*
- 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
- }
|