xref: /aosp_15_r20/external/tink/go/daead/subtle/aes_siv.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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