gitee.com/lh-her-team/common@v1.5.1/crypto/sym/aes/aes.go (about)

     1  package aes
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"encoding/asn1"
     8  	"encoding/hex"
     9  	"fmt"
    10  
    11  	"gitee.com/lh-her-team/common/crypto"
    12  	"gitee.com/lh-her-team/common/crypto/sym/modes"
    13  	"gitee.com/lh-her-team/common/crypto/sym/util"
    14  )
    15  
    16  const (
    17  	AES_GCM_IV_LENGTH  = 12
    18  	AES_GCM_TAG_LENGTH = 16
    19  )
    20  
    21  var defaultAESOpts = &crypto.EncOpts{
    22  	EncodingType: modes.PADDING_NONE,
    23  	BlockMode:    modes.BLOCK_MODE_GCM,
    24  	EnableMAC:    true,
    25  	Hash:         0,
    26  	Label:        nil,
    27  	EnableASN1:   true,
    28  }
    29  
    30  type AESKey struct {
    31  	Key []byte
    32  }
    33  
    34  type aesCiphertext struct {
    35  	IV         []byte
    36  	Ciphertext []byte
    37  	Tag        []byte
    38  }
    39  
    40  func (aesKey *AESKey) Bytes() ([]byte, error) {
    41  	return aesKey.Key, nil
    42  }
    43  
    44  func (aesKey *AESKey) String() (string, error) {
    45  	return hex.EncodeToString(aesKey.Key), nil
    46  }
    47  
    48  /*
    49    The ciphertext returned by Encrypt() and EncryptWithOpts can be ASN1 encoded,
    50    or of the form:
    51       nonce + ciphertext + tag (can be nil)
    52  */
    53  func (aesKey *AESKey) Encrypt(plain []byte) ([]byte, error) {
    54  	return aesKey.EncryptWithOpts(plain, defaultAESOpts)
    55  }
    56  
    57  func (aesKey *AESKey) EncryptWithOpts(plain []byte, opts *crypto.EncOpts) ([]byte, error) {
    58  	block, err := aes.NewCipher(aesKey.Key)
    59  	if err != nil {
    60  		return nil, fmt.Errorf("AES encryption fails: %v", err)
    61  	}
    62  	var ciphertext aesCiphertext
    63  	switch opts.BlockMode {
    64  	case modes.BLOCK_MODE_CBC:
    65  		var msg []byte
    66  		switch opts.EncodingType {
    67  		case modes.PADDING_PKCS5:
    68  			msg = util.PKCS5Padding(plain, block.BlockSize())
    69  		default:
    70  			return nil, fmt.Errorf("AES CBC encryption fails: invalid padding scheme [%s]", opts.EncodingType)
    71  		}
    72  		ciphertext.IV = make([]byte, block.BlockSize())
    73  		if _, err := rand.Read(ciphertext.IV); err != nil {
    74  			return nil, fmt.Errorf("AES CBC encryption fails: %v", err)
    75  		}
    76  		blockMode := cipher.NewCBCEncrypter(block, ciphertext.IV)
    77  		ciphertext.Ciphertext = make([]byte, len(msg))
    78  		blockMode.CryptBlocks(ciphertext.Ciphertext[0:], msg)
    79  		ciphertext.Tag = nil
    80  	case modes.BLOCK_MODE_GCM:
    81  		gcmMode, err := cipher.NewGCM(block)
    82  		if err != nil {
    83  			return nil, fmt.Errorf("AES GCM encryption fails: %v", err)
    84  		}
    85  		ivLength := gcmMode.NonceSize()
    86  		ciphertext.IV = make([]byte, ivLength)
    87  		if _, err := rand.Read(ciphertext.IV); err != nil {
    88  			return nil, fmt.Errorf("AES GCM encryption fails: %v", err)
    89  		}
    90  		cipherWithTag := gcmMode.Seal(nil, ciphertext.IV, plain, nil)
    91  		tagLength := gcmMode.Overhead()
    92  		ciphertext.Ciphertext = cipherWithTag[0 : len(cipherWithTag)-tagLength]
    93  		ciphertext.Tag = cipherWithTag[len(cipherWithTag)-tagLength:]
    94  	default:
    95  		return nil, fmt.Errorf("AES encryption fails: unknown cipher block mode [%s]", opts.BlockMode)
    96  	}
    97  	if opts.EnableASN1 {
    98  		return asn1.Marshal(ciphertext)
    99  	}
   100  	ret := append(ciphertext.IV, ciphertext.Ciphertext...)
   101  	ret = append(ret, ciphertext.Tag...)
   102  	return ret, nil
   103  }
   104  
   105  /*
   106    The input ciphertext can be ASN1 encoded,
   107    or of the form:
   108       nonce + ciphertext + tag (can be nil)
   109  */
   110  func (aesKey *AESKey) Decrypt(crypted []byte) ([]byte, error) {
   111  	return aesKey.DecryptWithOpts(crypted, defaultAESOpts)
   112  }
   113  
   114  func (aesKey *AESKey) DecryptWithOpts(crypted []byte, opts *crypto.EncOpts) ([]byte, error) {
   115  	var ciphertext aesCiphertext
   116  	if opts.EnableASN1 {
   117  		_, err := asn1.Unmarshal(crypted, &ciphertext)
   118  		if err != nil {
   119  			return nil, fmt.Errorf("AES decryption fails: %v", err)
   120  		}
   121  	}
   122  	block, err := aes.NewCipher(aesKey.Key)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("AES decryption fails: %v", err)
   125  	}
   126  	switch opts.BlockMode {
   127  	case modes.BLOCK_MODE_CBC:
   128  		if !opts.EnableASN1 {
   129  			ciphertext.IV = crypted[0:block.BlockSize()]
   130  			ciphertext.Ciphertext = crypted[block.BlockSize():]
   131  			ciphertext.Tag = nil
   132  		}
   133  		blockMode := cipher.NewCBCDecrypter(block, ciphertext.IV)
   134  		orig := make([]byte, len(ciphertext.Ciphertext))
   135  		blockMode.CryptBlocks(orig, ciphertext.Ciphertext)
   136  		switch opts.EncodingType {
   137  		case modes.PADDING_PKCS5:
   138  			orig, err = util.PKCS5UnPadding(orig)
   139  			if err != nil {
   140  				return nil, fmt.Errorf("AES CBC decryption fails: %v", err)
   141  			}
   142  			return orig, nil
   143  		default:
   144  			return nil, fmt.Errorf("AES CBC decryption fails: invalid padding scheme [%s]", opts.EncodingType)
   145  		}
   146  	case modes.BLOCK_MODE_GCM:
   147  		gcmMode, err := cipher.NewGCM(block)
   148  		if err != nil {
   149  			return nil, fmt.Errorf("AES GCM decryption fails: %v", err)
   150  		}
   151  		if !opts.EnableASN1 {
   152  			ciphertext.IV = crypted[0:gcmMode.NonceSize()]
   153  			ciphertext.Ciphertext = crypted[gcmMode.NonceSize() : len(crypted)-gcmMode.Overhead()]
   154  			ciphertext.Tag = crypted[len(crypted)-gcmMode.Overhead():]
   155  		}
   156  		cipherWithTag := append(ciphertext.Ciphertext, ciphertext.Tag...)
   157  		return gcmMode.Open(nil, ciphertext.IV, cipherWithTag, nil)
   158  	default:
   159  		return nil, fmt.Errorf("AES decryption fails: unknown cipher block mode [%s]", opts.BlockMode)
   160  	}
   161  }
   162  
   163  func (aesKey *AESKey) Type() crypto.KeyType {
   164  	return crypto.AES
   165  }