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