1// Copyright 2020 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package subtle 18 19import ( 20 "crypto/aes" 21 "crypto/cipher" 22 "fmt" 23 24 // Placeholder for internal crypto/cipher allowlist, please ignore. 25 "github.com/google/tink/go/subtle/random" 26) 27 28const ( 29 // AESCTRMinIVSize is the minimum IV size that this implementation supports. 30 AESCTRMinIVSize = 12 31) 32 33// AESCTR is an implementation of AEAD interface. 34type AESCTR struct { 35 Key []byte 36 IVSize int 37} 38 39// NewAESCTR returns an AESCTR instance. 40// The key argument should be the AES key, either 16 or 32 bytes to select 41// AES-128 or AES-256. 42// ivSize specifies the size of the IV in bytes. 43func NewAESCTR(key []byte, ivSize int) (*AESCTR, error) { 44 keySize := uint32(len(key)) 45 if err := ValidateAESKeySize(keySize); err != nil { 46 return nil, fmt.Errorf("aes_ctr: %s", err) 47 } 48 if ivSize < AESCTRMinIVSize || ivSize > aes.BlockSize { 49 return nil, fmt.Errorf("aes_ctr: invalid IV size: %d", ivSize) 50 } 51 return &AESCTR{Key: key, IVSize: ivSize}, nil 52} 53 54// Encrypt encrypts plaintext using AES in CTR mode. 55// The resulting ciphertext consists of two parts: 56// (1) the IV used for encryption and (2) the actual ciphertext. 57func (a *AESCTR) Encrypt(plaintext []byte) ([]byte, error) { 58 if len(plaintext) > maxInt-a.IVSize { 59 return nil, fmt.Errorf("aes_ctr: plaintext too long") 60 } 61 iv := a.newIV() 62 stream, err := newCipher(a.Key, iv) 63 if err != nil { 64 return nil, err 65 } 66 67 ciphertext := make([]byte, a.IVSize+len(plaintext)) 68 if n := copy(ciphertext, iv); n != a.IVSize { 69 return nil, fmt.Errorf("aes_ctr: failed to copy IV (copied %d/%d bytes)", n, a.IVSize) 70 } 71 72 stream.XORKeyStream(ciphertext[a.IVSize:], plaintext) 73 return ciphertext, nil 74} 75 76// Decrypt decrypts ciphertext. 77func (a *AESCTR) Decrypt(ciphertext []byte) ([]byte, error) { 78 if len(ciphertext) < a.IVSize { 79 return nil, fmt.Errorf("aes_ctr: ciphertext too short") 80 } 81 82 iv := ciphertext[:a.IVSize] 83 stream, err := newCipher(a.Key, iv) 84 if err != nil { 85 return nil, err 86 } 87 88 plaintext := make([]byte, len(ciphertext)-a.IVSize) 89 stream.XORKeyStream(plaintext, ciphertext[a.IVSize:]) 90 return plaintext, nil 91} 92 93// newIV creates a new IV for encryption. 94func (a *AESCTR) newIV() []byte { 95 return random.GetRandomBytes(uint32(a.IVSize)) 96} 97 98// newCipher creates a new AES-CTR cipher using the given key, IV and the crypto library. 99func newCipher(key, iv []byte) (cipher.Stream, error) { 100 block, err := aes.NewCipher(key) 101 if err != nil { 102 return nil, fmt.Errorf("aes_ctr: failed to create block cipher, error: %v", err) 103 } 104 105 // If the IV is less than BlockSize bytes we need to pad it with zeros 106 // otherwise NewCTR will panic. 107 if len(iv) < aes.BlockSize { 108 paddedIV := make([]byte, aes.BlockSize) 109 if n := copy(paddedIV, iv); n != len(iv) { 110 return nil, fmt.Errorf("aes_ctr: failed to pad IV") 111 } 112 return cipher.NewCTR(block, paddedIV), nil 113 } 114 115 return cipher.NewCTR(block, iv), nil 116} 117