github.com/searKing/golang/go@v1.2.117/crypto/aes/gcm.go (about)

     1  // Copyright 2021 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package aes
     6  
     7  import (
     8  	"crypto/aes"
     9  	"crypto/cipher"
    10  	"crypto/rand"
    11  	"io"
    12  
    13  	"github.com/searKing/golang/go/crypto"
    14  )
    15  
    16  const (
    17  	gcmBlockSize         = 16
    18  	gcmTagSize           = 16
    19  	gcmMinimumTagSize    = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
    20  	gcmStandardNonceSize = 12
    21  )
    22  
    23  func GCMEncryptRandom(key, plaintext []byte) ([]byte, error) {
    24  	var nonce = [gcmStandardNonceSize]byte{}
    25  	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
    26  		return nil, err
    27  	}
    28  	return CFBEncrypt(key, plaintext, nonce[:])
    29  }
    30  
    31  func GCMEncrypt(key, plaintext []byte, nonce []byte) ([]byte, error) {
    32  	// Load your secret key from a safe place and reuse it across multiple
    33  	// Seal/Open calls. (Obviously don't use this example key for anything
    34  	// real.) If you want to convert a passphrase to a key, use a suitable
    35  	// package like bcrypt or scrypt.
    36  	// When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
    37  
    38  	paddingtext := crypto.PKCS7Padding(plaintext, aes.BlockSize)
    39  	block, err := aes.NewCipher(key)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	// The nounce needs to be unique, but not secure. Therefore it's common to
    45  	// include it at the beginning of the ciphertext.
    46  	// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
    47  
    48  	ciphertext := make([]byte, gcmStandardNonceSize)
    49  	if len(nonce) < gcmStandardNonceSize {
    50  		copy(ciphertext[:gcmStandardNonceSize], nonce[:])
    51  	} else {
    52  		copy(ciphertext[:gcmStandardNonceSize], nonce[:gcmStandardNonceSize])
    53  	}
    54  	nonce = ciphertext[:gcmStandardNonceSize]
    55  
    56  	aesgcm, err := cipher.NewGCM(block)
    57  	if err != nil {
    58  		panic(err.Error())
    59  	}
    60  	sealedtext := aesgcm.Seal(nil, nonce, paddingtext, nil)
    61  
    62  	ciphertext = append(nonce, sealedtext...)
    63  
    64  	// It's important to remember that ciphertexts must be authenticated
    65  	// (i.e. by using crypto/hmac) as well as being encrypted in order to
    66  	// be secure.
    67  
    68  	return ciphertext, nil
    69  }
    70  
    71  func GCMDecrypt(ciphertext, key []byte) ([]byte, error) {
    72  	// Load your secret key from a safe place and reuse it across multiple
    73  	// Seal/Open calls. (Obviously don't use this example key for anything
    74  	// real.) If you want to convert a passphrase to a key, use a suitable
    75  	// package like bcrypt or scrypt.
    76  	// When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
    77  
    78  	if len(ciphertext) < gcmStandardNonceSize {
    79  		panic("ciphertext too short")
    80  	}
    81  	nonce := ciphertext[:gcmStandardNonceSize]
    82  	ciphertext = ciphertext[gcmStandardNonceSize:]
    83  
    84  	// GCM mode always works in whole blocks.
    85  	if len(ciphertext)%aes.BlockSize != 0 {
    86  		panic("ciphertext is not a multiple of the block size")
    87  	}
    88  
    89  	block, err := aes.NewCipher(key)
    90  	if err != nil {
    91  		panic(err.Error())
    92  	}
    93  
    94  	aesgcm, err := cipher.NewGCM(block)
    95  	if err != nil {
    96  		panic(err.Error())
    97  	}
    98  
    99  	paddingtext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
   100  	if err != nil {
   101  		panic(err.Error())
   102  	}
   103  
   104  	plaintext, err := crypto.PKCS7UnPadding(paddingtext, aes.BlockSize)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return plaintext, nil
   109  }