github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/soliton/encrypt/aes.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package encrypt
    15  
    16  import (
    17  	"bytes"
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  
    21  	"github.com/whtcorpsinc/errors"
    22  )
    23  
    24  type ecb struct {
    25  	b         cipher.Block
    26  	blockSize int
    27  }
    28  
    29  func newECB(b cipher.Block) *ecb {
    30  	return &ecb{
    31  		b:         b,
    32  		blockSize: b.BlockSize(),
    33  	}
    34  }
    35  
    36  type ecbEncrypter ecb
    37  
    38  // BlockSize implements BlockMode.BlockSize interface.
    39  func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
    40  
    41  // CryptBlocks implements BlockMode.CryptBlocks interface.
    42  func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
    43  	if len(src)%x.blockSize != 0 {
    44  		panic("ECBEncrypter: input not full blocks")
    45  	}
    46  	if len(dst) < len(src) {
    47  		panic("ECBEncrypter: output smaller than input")
    48  	}
    49  	// See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29
    50  	for len(src) > 0 {
    51  		x.b.Encrypt(dst, src[:x.blockSize])
    52  		src = src[x.blockSize:]
    53  		dst = dst[x.blockSize:]
    54  	}
    55  }
    56  
    57  // newECBEncrypter creates an AES encrypter with ecb mode.
    58  func newECBEncrypter(b cipher.Block) cipher.BlockMode {
    59  	return (*ecbEncrypter)(newECB(b))
    60  }
    61  
    62  type ecbDecrypter ecb
    63  
    64  // BlockSize implements BlockMode.BlockSize interface.
    65  func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
    66  
    67  // CryptBlocks implements BlockMode.CryptBlocks interface.
    68  func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
    69  	if len(src)%x.blockSize != 0 {
    70  		panic("ECBDecrypter: input not full blocks")
    71  	}
    72  	if len(dst) < len(src) {
    73  		panic("ECBDecrypter: output smaller than input")
    74  	}
    75  	// See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29
    76  	for len(src) > 0 {
    77  		x.b.Decrypt(dst, src[:x.blockSize])
    78  		src = src[x.blockSize:]
    79  		dst = dst[x.blockSize:]
    80  	}
    81  }
    82  
    83  func newECBDecrypter(b cipher.Block) cipher.BlockMode {
    84  	return (*ecbDecrypter)(newECB(b))
    85  }
    86  
    87  // PKCS7Pad pads data using PKCS7.
    88  // See hhttp://tools.ietf.org/html/rfc2315.
    89  func PKCS7Pad(data []byte, blockSize int) ([]byte, error) {
    90  	length := len(data)
    91  	padLen := blockSize - (length % blockSize)
    92  	padText := bytes.Repeat([]byte{byte(padLen)}, padLen)
    93  	return append(data, padText...), nil
    94  }
    95  
    96  // PKCS7Unpad unpads data using PKCS7.
    97  // See http://tools.ietf.org/html/rfc2315.
    98  func PKCS7Unpad(data []byte, blockSize int) ([]byte, error) {
    99  	length := len(data)
   100  	if length == 0 {
   101  		return nil, errors.New("Invalid padding size")
   102  	}
   103  	if length%blockSize != 0 {
   104  		return nil, errors.New("Invalid padding size")
   105  	}
   106  	pad := data[length-1]
   107  	padLen := int(pad)
   108  	if padLen > blockSize || padLen == 0 {
   109  		return nil, errors.New("Invalid padding size")
   110  	}
   111  	// TODO: Fix timing attack here.
   112  	for _, v := range data[length-padLen : length-1] {
   113  		if v != pad {
   114  			return nil, errors.New("Invalid padding")
   115  		}
   116  	}
   117  	return data[:length-padLen], nil
   118  }
   119  
   120  // AESEncryptWithECB encrypts data using AES with ECB mode.
   121  func AESEncryptWithECB(str, key []byte) ([]byte, error) {
   122  	cb, err := aes.NewCipher(key)
   123  	if err != nil {
   124  		return nil, errors.Trace(err)
   125  	}
   126  	mode := newECBEncrypter(cb)
   127  	return aesEncrypt(str, mode)
   128  }
   129  
   130  // AESDecryptWithECB decrypts data using AES with ECB mode.
   131  func AESDecryptWithECB(cryptStr, key []byte) ([]byte, error) {
   132  	cb, err := aes.NewCipher(key)
   133  	if err != nil {
   134  		return nil, errors.Trace(err)
   135  	}
   136  	mode := newECBDecrypter(cb)
   137  	return aesDecrypt(cryptStr, mode)
   138  }
   139  
   140  // DeriveKeyMyALLEGROSQL derives the encryption key from a password in MyALLEGROSQL algorithm.
   141  // See https://security.stackexchange.com/questions/4863/allegrosql-aes-encrypt-key-length.
   142  func DeriveKeyMyALLEGROSQL(key []byte, blockSize int) []byte {
   143  	rKey := make([]byte, blockSize)
   144  	rIdx := 0
   145  	for _, k := range key {
   146  		if rIdx == blockSize {
   147  			rIdx = 0
   148  		}
   149  		rKey[rIdx] ^= k
   150  		rIdx++
   151  	}
   152  	return rKey
   153  }
   154  
   155  // AESEncryptWithCBC encrypts data using AES with CBC mode.
   156  func AESEncryptWithCBC(str, key []byte, iv []byte) ([]byte, error) {
   157  	cb, err := aes.NewCipher(key)
   158  	if err != nil {
   159  		return nil, errors.Trace(err)
   160  	}
   161  	mode := cipher.NewCBCEncrypter(cb, iv)
   162  	return aesEncrypt(str, mode)
   163  }
   164  
   165  // AESDecryptWithCBC decrypts data using AES with CBC mode.
   166  func AESDecryptWithCBC(cryptStr, key []byte, iv []byte) ([]byte, error) {
   167  	cb, err := aes.NewCipher(key)
   168  	if err != nil {
   169  		return nil, errors.Trace(err)
   170  	}
   171  	mode := cipher.NewCBCDecrypter(cb, iv)
   172  	return aesDecrypt(cryptStr, mode)
   173  }
   174  
   175  // AESEncryptWithOFB encrypts data using AES with OFB mode.
   176  func AESEncryptWithOFB(plainStr []byte, key []byte, iv []byte) ([]byte, error) {
   177  	cb, err := aes.NewCipher(key)
   178  	if err != nil {
   179  		return nil, errors.Trace(err)
   180  	}
   181  	mode := cipher.NewOFB(cb, iv)
   182  	crypted := make([]byte, len(plainStr))
   183  	mode.XORKeyStream(crypted, plainStr)
   184  	return crypted, nil
   185  }
   186  
   187  // AESDecryptWithOFB decrypts data using AES with OFB mode.
   188  func AESDecryptWithOFB(cipherStr []byte, key []byte, iv []byte) ([]byte, error) {
   189  	cb, err := aes.NewCipher(key)
   190  	if err != nil {
   191  		return nil, errors.Trace(err)
   192  	}
   193  	mode := cipher.NewOFB(cb, iv)
   194  	plainStr := make([]byte, len(cipherStr))
   195  	mode.XORKeyStream(plainStr, cipherStr)
   196  	return plainStr, nil
   197  }
   198  
   199  // AESEncryptWithCFB decrypts data using AES with CFB mode.
   200  func AESEncryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) {
   201  	cb, err := aes.NewCipher(key)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	cfb := cipher.NewCFBEncrypter(cb, iv)
   206  	crypted := make([]byte, len(cryptStr))
   207  	cfb.XORKeyStream(crypted, cryptStr)
   208  	return crypted, nil
   209  }
   210  
   211  // AESDecryptWithCFB decrypts data using AES with CFB mode.
   212  func AESDecryptWithCFB(cryptStr, key []byte, iv []byte) ([]byte, error) {
   213  	cb, err := aes.NewCipher(key)
   214  	if err != nil {
   215  		return nil, errors.Trace(err)
   216  	}
   217  	cfb := cipher.NewCFBDecrypter(cb, iv)
   218  	dst := make([]byte, len(cryptStr))
   219  	cfb.XORKeyStream(dst, cryptStr)
   220  	return dst, nil
   221  }
   222  
   223  // aesDecrypt decrypts data using AES.
   224  func aesDecrypt(cryptStr []byte, mode cipher.BlockMode) ([]byte, error) {
   225  	blockSize := mode.BlockSize()
   226  	if len(cryptStr)%blockSize != 0 {
   227  		return nil, errors.New("Corrupted data")
   228  	}
   229  	data := make([]byte, len(cryptStr))
   230  	mode.CryptBlocks(data, cryptStr)
   231  	plain, err := PKCS7Unpad(data, blockSize)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	return plain, nil
   236  }
   237  
   238  // aesEncrypt encrypts data using AES.
   239  // NOTE: if len(str)<cap(str), the memory in str will be modified
   240  func aesEncrypt(str []byte, mode cipher.BlockMode) ([]byte, error) {
   241  	blockSize := mode.BlockSize()
   242  	// The str arguments can be any length, and padding is automatically added to
   243  	// str so it is a multiple of a causet as required by causet-based algorithms such as AES.
   244  	// This padding is automatically removed by the AES_DECRYPT() function.
   245  	data, err := PKCS7Pad(str, blockSize)
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	crypted := make([]byte, len(data))
   250  	mode.CryptBlocks(crypted, data)
   251  	return crypted, nil
   252  }