github.com/lingyao2333/mo-zero@v1.4.1/core/codec/aesecb.go (about)

     1  package codec
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"encoding/base64"
     8  	"errors"
     9  
    10  	"github.com/lingyao2333/mo-zero/core/logx"
    11  )
    12  
    13  // ErrPaddingSize indicates bad padding size.
    14  var ErrPaddingSize = errors.New("padding size error")
    15  
    16  type ecb struct {
    17  	b         cipher.Block
    18  	blockSize int
    19  }
    20  
    21  func newECB(b cipher.Block) *ecb {
    22  	return &ecb{
    23  		b:         b,
    24  		blockSize: b.BlockSize(),
    25  	}
    26  }
    27  
    28  type ecbEncrypter ecb
    29  
    30  // NewECBEncrypter returns an ECB encrypter.
    31  func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
    32  	return (*ecbEncrypter)(newECB(b))
    33  }
    34  
    35  func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
    36  
    37  // why we don't return error is because cipher.BlockMode doesn't allow this
    38  func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
    39  	if len(src)%x.blockSize != 0 {
    40  		logx.Error("crypto/cipher: input not full blocks")
    41  		return
    42  	}
    43  	if len(dst) < len(src) {
    44  		logx.Error("crypto/cipher: output smaller than input")
    45  		return
    46  	}
    47  
    48  	for len(src) > 0 {
    49  		x.b.Encrypt(dst, src[:x.blockSize])
    50  		src = src[x.blockSize:]
    51  		dst = dst[x.blockSize:]
    52  	}
    53  }
    54  
    55  type ecbDecrypter ecb
    56  
    57  // NewECBDecrypter returns an ECB decrypter.
    58  func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
    59  	return (*ecbDecrypter)(newECB(b))
    60  }
    61  
    62  func (x *ecbDecrypter) BlockSize() int {
    63  	return x.blockSize
    64  }
    65  
    66  // why we don't return error is because cipher.BlockMode doesn't allow this
    67  func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
    68  	if len(src)%x.blockSize != 0 {
    69  		logx.Error("crypto/cipher: input not full blocks")
    70  		return
    71  	}
    72  	if len(dst) < len(src) {
    73  		logx.Error("crypto/cipher: output smaller than input")
    74  		return
    75  	}
    76  
    77  	for len(src) > 0 {
    78  		x.b.Decrypt(dst, src[:x.blockSize])
    79  		src = src[x.blockSize:]
    80  		dst = dst[x.blockSize:]
    81  	}
    82  }
    83  
    84  // EcbDecrypt decrypts src with the given key.
    85  func EcbDecrypt(key, src []byte) ([]byte, error) {
    86  	block, err := aes.NewCipher(key)
    87  	if err != nil {
    88  		logx.Errorf("Decrypt key error: % x", key)
    89  		return nil, err
    90  	}
    91  
    92  	decrypter := NewECBDecrypter(block)
    93  	decrypted := make([]byte, len(src))
    94  	decrypter.CryptBlocks(decrypted, src)
    95  
    96  	return pkcs5Unpadding(decrypted, decrypter.BlockSize())
    97  }
    98  
    99  // EcbDecryptBase64 decrypts base64 encoded src with the given base64 encoded key.
   100  // The returned string is also base64 encoded.
   101  func EcbDecryptBase64(key, src string) (string, error) {
   102  	keyBytes, err := getKeyBytes(key)
   103  	if err != nil {
   104  		return "", err
   105  	}
   106  
   107  	encryptedBytes, err := base64.StdEncoding.DecodeString(src)
   108  	if err != nil {
   109  		return "", err
   110  	}
   111  
   112  	decryptedBytes, err := EcbDecrypt(keyBytes, encryptedBytes)
   113  	if err != nil {
   114  		return "", err
   115  	}
   116  
   117  	return base64.StdEncoding.EncodeToString(decryptedBytes), nil
   118  }
   119  
   120  // EcbEncrypt encrypts src with the given key.
   121  func EcbEncrypt(key, src []byte) ([]byte, error) {
   122  	block, err := aes.NewCipher(key)
   123  	if err != nil {
   124  		logx.Errorf("Encrypt key error: % x", key)
   125  		return nil, err
   126  	}
   127  
   128  	padded := pkcs5Padding(src, block.BlockSize())
   129  	crypted := make([]byte, len(padded))
   130  	encrypter := NewECBEncrypter(block)
   131  	encrypter.CryptBlocks(crypted, padded)
   132  
   133  	return crypted, nil
   134  }
   135  
   136  // EcbEncryptBase64 encrypts base64 encoded src with the given base64 encoded key.
   137  // The returned string is also base64 encoded.
   138  func EcbEncryptBase64(key, src string) (string, error) {
   139  	keyBytes, err := getKeyBytes(key)
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  
   144  	srcBytes, err := base64.StdEncoding.DecodeString(src)
   145  	if err != nil {
   146  		return "", err
   147  	}
   148  
   149  	encryptedBytes, err := EcbEncrypt(keyBytes, srcBytes)
   150  	if err != nil {
   151  		return "", err
   152  	}
   153  
   154  	return base64.StdEncoding.EncodeToString(encryptedBytes), nil
   155  }
   156  
   157  func getKeyBytes(key string) ([]byte, error) {
   158  	if len(key) <= 32 {
   159  		return []byte(key), nil
   160  	}
   161  
   162  	keyBytes, err := base64.StdEncoding.DecodeString(key)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	return keyBytes, nil
   168  }
   169  
   170  func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
   171  	padding := blockSize - len(ciphertext)%blockSize
   172  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
   173  	return append(ciphertext, padtext...)
   174  }
   175  
   176  func pkcs5Unpadding(src []byte, blockSize int) ([]byte, error) {
   177  	length := len(src)
   178  	unpadding := int(src[length-1])
   179  	if unpadding >= length || unpadding > blockSize {
   180  		return nil, ErrPaddingSize
   181  	}
   182  
   183  	return src[:length-unpadding], nil
   184  }