github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/aead/subtle/gojose_aes_cbc_hmac.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package subtle
     8  
     9  import (
    10  	"crypto/aes"
    11  	"errors"
    12  	"fmt"
    13  
    14  	josecipher "github.com/go-jose/go-jose/v3/cipher"
    15  	"github.com/google/tink/go/subtle/random"
    16  )
    17  
    18  // AESCBCHMAC is an implementation of AEAD interface.
    19  type AESCBCHMAC struct {
    20  	Key []byte
    21  }
    22  
    23  // NewAESCBCHMAC returns an AES CBC HMAC instance.
    24  // The key argument should be the AES key, either 16, 24 or 32 bytes to select AES-128, AES-192 or AES-256.
    25  // ivSize specifies the size of the IV in bytes.
    26  func NewAESCBCHMAC(key []byte) (*AESCBCHMAC, error) {
    27  	keySize := uint32(len(key))
    28  
    29  	if err := ValidateAESKeySizeForGoJose(keySize); err != nil {
    30  		return nil, fmt.Errorf("aes_cbc_hmac: %w", err)
    31  	}
    32  
    33  	return &AESCBCHMAC{Key: key}, nil
    34  }
    35  
    36  // Encrypt encrypts plaintext using AES in CTR mode.
    37  // The resulting ciphertext consists of two parts:
    38  // (1) a random IV used for encryption and (2) the actual ciphertext.
    39  func (a *AESCBCHMAC) Encrypt(plaintext, additionalData []byte) ([]byte, error) {
    40  	if len(plaintext) > maxInt-AESCBCIVSize {
    41  		return nil, errors.New("aes_cbc_hmac: plaintext too long")
    42  	}
    43  
    44  	iv := a.newIV()
    45  
    46  	cbcHMAC, err := josecipher.NewCBCHMAC(a.Key, aes.NewCipher)
    47  	if err != nil {
    48  		return nil, fmt.Errorf("aes_cbc_hmac: %w", err)
    49  	}
    50  
    51  	ciphertext := cbcHMAC.Seal(nil, iv, plaintext, additionalData)
    52  
    53  	ciphertextAndIV := make([]byte, AESCBCIVSize+len(ciphertext))
    54  	if n := copy(ciphertextAndIV, iv); n != AESCBCIVSize {
    55  		return nil, fmt.Errorf("aes_cbc_hmac: failed to copy IV (copied %d/%d bytes)", n, AESCBCIVSize)
    56  	}
    57  
    58  	copy(ciphertextAndIV[AESCBCIVSize:], ciphertext)
    59  
    60  	return ciphertextAndIV, nil
    61  }
    62  
    63  // Decrypt decrypts ciphertext.
    64  func (a *AESCBCHMAC) Decrypt(ciphertext, additionalData []byte) ([]byte, error) {
    65  	cbcAEAD, err := josecipher.NewCBCHMAC(a.Key, aes.NewCipher)
    66  	if err != nil {
    67  		return nil, fmt.Errorf("aes_cbc_hmac: %w", err)
    68  	}
    69  
    70  	ivSize := cbcAEAD.NonceSize()
    71  	if len(ciphertext) < ivSize {
    72  		return nil, errors.New("aes_cbc_hmac: ciphertext too short")
    73  	}
    74  
    75  	iv := ciphertext[:ivSize]
    76  
    77  	plaintext, err := cbcAEAD.Open(nil, iv, ciphertext[ivSize:], additionalData)
    78  	if err != nil {
    79  		return nil, fmt.Errorf("aes_cbc_hmac: failed to decrypt: %w", err)
    80  	}
    81  
    82  	return plaintext, nil
    83  }
    84  
    85  // newIV creates a new IV for encryption.
    86  func (a *AESCBCHMAC) newIV() []byte {
    87  	return random.GetRandomBytes(uint32(AESCBCIVSize))
    88  }