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 17// Package subtle provides subtle implementations of the DeterministicAEAD 18// primitive. 19package subtle 20 21import ( 22 "crypto/aes" 23 "crypto/cipher" 24 "crypto/subtle" 25 "errors" 26 "fmt" 27 "math" 28 29 // Placeholder for internal crypto/cipher allowlist, please ignore. 30 // Placeholder for internal crypto/subtle allowlist, please ignore. 31) 32 33// AESSIV is an implementation of AES-SIV-CMAC as defined in 34// https://tools.ietf.org/html/rfc5297. 35// 36// AESSIV implements a deterministic encryption with associated data (i.e. the 37// DeterministicAEAD interface). Hence the implementation below is restricted 38// to one AD component. 39// 40// Security Note: 41// 42// Chatterjee, Menezes and Sarkar analyze AES-SIV in Section 5.1 of 43// https://www.math.uwaterloo.ca/~ajmeneze/publications/tightness.pdf 44// 45// Their analysis shows that AES-SIV is susceptible to an attack in 46// a multi-user setting. Concretely, if an attacker knows the encryption 47// of a message m encrypted and authenticated with k different keys, 48// then it is possible to find one of the MAC keys in time 2^b / k 49// where b is the size of the MAC key. A consequence of this attack 50// is that 128-bit MAC keys give unsufficient security. 51// Since 192-bit AES keys are not supported by tink for voodoo reasons 52// and RFC 5297 only supports same size encryption and MAC keys this 53// implies that keys must be 64 bytes (2*256 bits) long. 54type AESSIV struct { 55 K1 []byte 56 K2 []byte 57 CmacK1 []byte 58 CmacK2 []byte 59 Cipher cipher.Block 60} 61 62const ( 63 // AESSIVKeySize is the key size in bytes. 64 AESSIVKeySize = 64 65 66 intSize = 32 << (^uint(0) >> 63) // 32 or 64 67 maxInt = 1<<(intSize-1) - 1 68) 69 70// NewAESSIV returns an AESSIV instance. 71func NewAESSIV(key []byte) (*AESSIV, error) { 72 if len(key) != AESSIVKeySize { 73 return nil, fmt.Errorf("aes_siv: invalid key size %d", len(key)) 74 } 75 76 k1 := key[:32] 77 k2 := key[32:] 78 c, err := aes.NewCipher(k1) 79 if err != nil { 80 return nil, fmt.Errorf("aes_siv: aes.NewCipher(%s) failed, %v", k1, err) 81 } 82 83 block := make([]byte, aes.BlockSize) 84 c.Encrypt(block, block) 85 multiplyByX(block) 86 cmacK1 := make([]byte, aes.BlockSize) 87 copy(cmacK1, block) 88 multiplyByX(block) 89 cmacK2 := make([]byte, aes.BlockSize) 90 copy(cmacK2, block) 91 92 return &AESSIV{ 93 K1: k1, 94 K2: k2, 95 CmacK1: cmacK1, 96 CmacK2: cmacK2, 97 Cipher: c, 98 }, nil 99} 100 101// multiplyByX multiplies an element in GF(2^128) by its generator. 102// 103// This function is incorrectly named "doubling" in section 2.3 of RFC 5297. 104func multiplyByX(block []byte) { 105 carry := int(block[0] >> 7) 106 for i := 0; i < aes.BlockSize-1; i++ { 107 block[i] = (block[i] << 1) | (block[i+1] >> 7) 108 } 109 110 block[aes.BlockSize-1] = (block[aes.BlockSize-1] << 1) ^ byte(subtle.ConstantTimeSelect(carry, 0x87, 0x00)) 111} 112 113// EncryptDeterministically deterministically encrypts plaintext with associatedData. 114func (asc *AESSIV) EncryptDeterministically(plaintext, associatedData []byte) ([]byte, error) { 115 if len(plaintext) > maxInt-aes.BlockSize { 116 return nil, fmt.Errorf("aes_siv: plaintext too long") 117 } 118 siv := make([]byte, aes.BlockSize) 119 asc.s2v(plaintext, associatedData, siv) 120 121 ct := make([]byte, len(plaintext)+aes.BlockSize) 122 copy(ct[:aes.BlockSize], siv) 123 if err := asc.ctrCrypt(siv, plaintext, ct[aes.BlockSize:]); err != nil { 124 return nil, err 125 } 126 127 return ct, nil 128} 129 130// DecryptDeterministically deterministically decrypts ciphertext with associatedData. 131func (asc *AESSIV) DecryptDeterministically(ciphertext, associatedData []byte) ([]byte, error) { 132 if len(ciphertext) < aes.BlockSize { 133 return nil, errors.New("aes_siv: ciphertext is too short") 134 } 135 136 pt := make([]byte, len(ciphertext)-aes.BlockSize) 137 siv := ciphertext[:aes.BlockSize] 138 asc.ctrCrypt(siv, ciphertext[aes.BlockSize:], pt) 139 s2v := make([]byte, aes.BlockSize) 140 asc.s2v(pt, associatedData, s2v) 141 142 diff := byte(0) 143 for i := 0; i < aes.BlockSize; i++ { 144 diff |= siv[i] ^ s2v[i] 145 } 146 if diff != 0 { 147 return nil, errors.New("aes_siv: invalid ciphertext") 148 } 149 150 return pt, nil 151} 152 153// ctrCrypt encrypts (or decrypts) the bytes in in using an SIV and writes the 154// result to out. 155func (asc *AESSIV) ctrCrypt(siv, in, out []byte) error { 156 // siv might be used outside of ctrCrypt(), so making a copy of it. 157 iv := make([]byte, aes.BlockSize) 158 copy(iv, siv) 159 iv[8] &= 0x7f 160 iv[12] &= 0x7f 161 162 c, err := aes.NewCipher(asc.K2) 163 if err != nil { 164 return fmt.Errorf("aes_siv: aes.NewCipher(%s) failed, %v", asc.K2, err) 165 } 166 167 steam := cipher.NewCTR(c, iv) 168 steam.XORKeyStream(out, in) 169 return nil 170} 171 172// s2v is a Pseudo-Random Function (PRF) construction: 173// https://tools.ietf.org/html/rfc5297. 174func (asc *AESSIV) s2v(msg, ad, siv []byte) { 175 block := make([]byte, aes.BlockSize) 176 asc.cmac(block, block) 177 multiplyByX(block) 178 179 adMac := make([]byte, aes.BlockSize) 180 asc.cmac(ad, adMac) 181 xorBlock(adMac, block) 182 183 if len(msg) >= aes.BlockSize { 184 asc.cmacLong(msg, block, siv) 185 } else { 186 multiplyByX(block) 187 for i := 0; i < len(msg); i++ { 188 block[i] ^= msg[i] 189 } 190 block[len(msg)] ^= 0x80 191 asc.cmac(block, siv) 192 } 193} 194 195// cmacLong computes CMAC(XorEnd(data, last)), where XorEnd xors the bytes in 196// last to the last bytes in data. 197// 198// The size of the data must be at least 16 bytes. 199func (asc *AESSIV) cmacLong(data, last, mac []byte) { 200 block := make([]byte, aes.BlockSize) 201 copy(block, data[:aes.BlockSize]) 202 203 idx := aes.BlockSize 204 for aes.BlockSize <= len(data)-idx { 205 asc.Cipher.Encrypt(block, block) 206 xorBlock(data[idx:idx+aes.BlockSize], block) 207 idx += aes.BlockSize 208 } 209 210 remaining := len(data) - idx 211 for i := 0; i < aes.BlockSize-remaining; i++ { 212 block[remaining+i] ^= last[i] 213 } 214 if remaining == 0 { 215 xorBlock(asc.CmacK1, block) 216 } else { 217 asc.Cipher.Encrypt(block, block) 218 for i := 0; i < remaining; i++ { 219 block[i] ^= last[aes.BlockSize-remaining+i] 220 block[i] ^= data[idx+i] 221 } 222 block[remaining] ^= 0x80 223 xorBlock(asc.CmacK2, block) 224 } 225 226 asc.Cipher.Encrypt(mac, block) 227} 228 229// cmac computes a CMAC of some data. 230func (asc *AESSIV) cmac(data, mac []byte) { 231 numBs := int(math.Ceil(float64(len(data)) / aes.BlockSize)) 232 if numBs == 0 { 233 numBs = 1 234 } 235 lastBSize := len(data) - (numBs-1)*aes.BlockSize 236 237 block := make([]byte, aes.BlockSize) 238 idx := 0 239 for i := 0; i < numBs-1; i++ { 240 xorBlock(data[idx:idx+aes.BlockSize], block) 241 asc.Cipher.Encrypt(block, block) 242 idx += aes.BlockSize 243 } 244 for j := 0; j < lastBSize; j++ { 245 block[j] ^= data[idx+j] 246 } 247 248 if lastBSize == aes.BlockSize { 249 xorBlock(asc.CmacK1, block) 250 } else { 251 block[lastBSize] ^= 0x80 252 xorBlock(asc.CmacK2, block) 253 } 254 255 asc.Cipher.Encrypt(mac, block) 256} 257 258// xorBlock sets block[i] = x[i] ^ block[i]. 259func xorBlock(x, block []byte) { 260 for i := 0; i < aes.BlockSize; i++ { 261 block[i] ^= x[i] 262 } 263} 264