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 }