1 // Copyright 2025 The BoringSSL Authors
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 //     https://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 #include <openssl/aead.h>
16 
17 #include <assert.h>
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <sys/types.h>
21 
22 #include <openssl/aes.h>
23 #include <openssl/base.h>
24 #include <openssl/cipher.h>
25 #include <openssl/crypto.h>
26 #include <openssl/err.h>
27 #include <openssl/mem.h>
28 
29 #include "../fipsmodule/cipher/internal.h"
30 #include "../internal.h"
31 
32 // Implementation of AES-EAX defined in
33 // https://www.iacr.org/archive/fse2004/30170391/30170391.pdf.
34 
35 #define EVP_AEAD_AES_EAX_TAG_LEN AES_BLOCK_SIZE
36 
37 struct aead_aes_eax_ctx {
38   union {
39     double align;
40     AES_KEY ks;
41   } ks;
42   uint8_t b[AES_BLOCK_SIZE];
43   uint8_t p[AES_BLOCK_SIZE];
44 };
45 
mult_by_X(uint8_t out[AES_BLOCK_SIZE],const uint8_t in[AES_BLOCK_SIZE])46 static void mult_by_X(uint8_t out[AES_BLOCK_SIZE],
47                       const uint8_t in[AES_BLOCK_SIZE]) {
48   const crypto_word_t in_hi = CRYPTO_load_word_be(in);
49   for (size_t i = 0; i < AES_BLOCK_SIZE - 1; ++i) {
50     out[i] = (in[i] << 1) | (in[i + 1] >> 7);
51   }
52   // Carry over 0x87 if msb is 1, 0x00 if msb is 0.
53   out[AES_BLOCK_SIZE - 1] = in[AES_BLOCK_SIZE - 1] << 1;
54   const uint8_t p = 0x87;
55   constant_time_conditional_memxor(out + AES_BLOCK_SIZE - 1, &p, /*n=*/1,
56                                    constant_time_msb_w(in_hi));
57 }
58 
aead_aes_eax_init(EVP_AEAD_CTX * ctx,const uint8_t * key,size_t key_len,size_t tag_len)59 static int aead_aes_eax_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
60                              size_t key_len, size_t tag_len) {
61   struct aead_aes_eax_ctx *aes_ctx = (struct aead_aes_eax_ctx *)&ctx->state;
62 
63   if (key_len != 16 && key_len != 32) {
64     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
65     return 0;
66   }
67 
68   if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
69     tag_len = EVP_AEAD_AES_EAX_TAG_LEN;
70   }
71 
72   if (tag_len != EVP_AEAD_AES_EAX_TAG_LEN) {
73     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
74     return 0;
75   }
76 
77   if (AES_set_encrypt_key(key, /*bits=*/key_len * 8, &aes_ctx->ks.ks) != 0) {
78     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED);
79     return 0;
80   }
81   ctx->tag_len = tag_len;
82 
83   // L <- Ek(0^n).
84   OPENSSL_memset(aes_ctx->b, 0, sizeof(aes_ctx->b));
85   AES_encrypt(aes_ctx->b, aes_ctx->b, &aes_ctx->ks.ks);
86   // B <- 2L.
87   mult_by_X(aes_ctx->b, aes_ctx->b);
88   // P <- 4L = 2B.
89   mult_by_X(aes_ctx->p, aes_ctx->b);
90   return 1;
91 }
92 
aead_aes_eax_cleanup(EVP_AEAD_CTX * ctx)93 static void aead_aes_eax_cleanup(EVP_AEAD_CTX *ctx) {}
94 
95 // Implements the CBK function in the paper.
cbk_block(const struct aead_aes_eax_ctx * aes_ctx,const uint8_t in[AES_BLOCK_SIZE],uint8_t out[AES_BLOCK_SIZE])96 static void cbk_block(const struct aead_aes_eax_ctx *aes_ctx,
97                       const uint8_t in[AES_BLOCK_SIZE],
98                       uint8_t out[AES_BLOCK_SIZE]) {
99   CRYPTO_xor16(out, in, out);
100   AES_encrypt(out, out, &aes_ctx->ks.ks);
101 }
102 
103 // Precondition: in_len <= AES_BLOCK_SIZE.
pad(const struct aead_aes_eax_ctx * aes_ctx,uint8_t out[AES_BLOCK_SIZE],const uint8_t * in,size_t in_len)104 static void pad(const struct aead_aes_eax_ctx *aes_ctx,
105                 uint8_t out[AES_BLOCK_SIZE], const uint8_t *in, size_t in_len) {
106   assert(in_len <= AES_BLOCK_SIZE);
107   if (in_len == AES_BLOCK_SIZE) {
108     CRYPTO_xor16(out, aes_ctx->b, in);
109     return;
110   }
111   OPENSSL_memset(out, 0, AES_BLOCK_SIZE);
112   OPENSSL_memcpy(out, in, in_len);
113   out[in_len] = 0x80;
114   CRYPTO_xor16(out, aes_ctx->p, out);
115 }
116 
omac(const struct aead_aes_eax_ctx * aes_ctx,uint8_t out[AES_BLOCK_SIZE],const uint8_t * in,size_t in_len)117 static void omac(const struct aead_aes_eax_ctx *aes_ctx,
118                  uint8_t out[AES_BLOCK_SIZE], const uint8_t *in,
119                  size_t in_len) {
120   if (in_len == 0) {
121     // CBK(pad(M;B,P)) = CBK(B). Avoiding padding to skip a copy.
122     cbk_block(aes_ctx, aes_ctx->b, out);
123     return;
124   }
125   // CBK(M1) = Ek(M1 ^ 0^n)
126   AES_encrypt(out, out, &aes_ctx->ks.ks);
127   while (in_len > AES_BLOCK_SIZE) {
128     // Full blocks, no padding needed.
129     cbk_block(aes_ctx, in, out);
130     in += AES_BLOCK_SIZE;
131     in_len -= AES_BLOCK_SIZE;
132   }
133   // Last block to be padded.
134   uint8_t padded_block[AES_BLOCK_SIZE];
135   pad(aes_ctx, padded_block, in, in_len);
136   cbk_block(aes_ctx, padded_block, out);
137 }
138 
omac_with_tag(const struct aead_aes_eax_ctx * aes_ctx,uint8_t out[AES_BLOCK_SIZE],const uint8_t * in,size_t in_len,int tag)139 static void omac_with_tag(const struct aead_aes_eax_ctx *aes_ctx,
140                           uint8_t out[AES_BLOCK_SIZE], const uint8_t *in,
141                           size_t in_len, int tag) {
142   OPENSSL_memset(out, 0, AES_BLOCK_SIZE);
143   out[AES_BLOCK_SIZE - 1] = tag;
144   omac(aes_ctx, out, in, in_len);
145 }
146 
147 // Encrypts/decrypts |in_len| bytes from |in| to |out| using AES-CTR with |n| as
148 // the IV.
aes_ctr(const struct aead_aes_eax_ctx * aes_ctx,uint8_t * out,const uint8_t n[AES_BLOCK_SIZE],const uint8_t * in,size_t in_len)149 static void aes_ctr(const struct aead_aes_eax_ctx *aes_ctx, uint8_t *out,
150                     const uint8_t n[AES_BLOCK_SIZE], const uint8_t *in,
151                     size_t in_len) {
152   uint8_t ivec[AES_BLOCK_SIZE];
153   OPENSSL_memcpy(ivec, n, AES_BLOCK_SIZE);
154 
155   uint8_t unused_ecount_buf[AES_BLOCK_SIZE];
156   unsigned int unused_num = 0;
157   AES_ctr128_encrypt(in, out, in_len, &aes_ctx->ks.ks, ivec, unused_ecount_buf,
158                      &unused_num);
159 }
160 
aead_aes_eax_seal_scatter(const EVP_AEAD_CTX * ctx,uint8_t * out,uint8_t * out_tag,size_t * out_tag_len,size_t max_out_tag_len,const uint8_t * nonce,size_t nonce_len,const uint8_t * in,size_t in_len,const uint8_t * extra_in,size_t extra_in_len,const uint8_t * ad,size_t ad_len)161 static int aead_aes_eax_seal_scatter(
162     const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
163     size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
164     size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
165     size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
166   assert(extra_in_len == 0);
167   // We use the full 128 bits of the nonce as counter, so no need to check the
168   // plaintext size.
169 
170   if (max_out_tag_len < ctx->tag_len) {
171     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
172     return 0;
173   }
174 
175   if (nonce_len != 12 && nonce_len != 16) {
176     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
177     return 0;
178   }
179 
180   const struct aead_aes_eax_ctx *aes_ctx =
181       (struct aead_aes_eax_ctx *)&ctx->state;
182 
183   // N <- OMAC(0 || nonce)
184   uint8_t n[AES_BLOCK_SIZE];
185   omac_with_tag(aes_ctx, n, nonce, nonce_len, /*tag=*/0);
186   // H <- OMAC(1 || ad)
187   uint8_t h[AES_BLOCK_SIZE];
188   omac_with_tag(aes_ctx, h, ad, ad_len, /*tag=*/1);
189 
190   // C <- CTR^{N}_{K}(M)
191   aes_ctr(aes_ctx, out, n, in, in_len);
192 
193   // MAC <- OMAC(2 || C)
194   omac_with_tag(aes_ctx, out_tag, out, in_len, /*tag=*/2);
195   // MAC <- N ^ C ^ H
196   CRYPTO_xor16(out_tag, n, out_tag);
197   CRYPTO_xor16(out_tag, h, out_tag);
198 
199   *out_tag_len = ctx->tag_len;
200   return 1;
201 }
202 
aead_aes_eax_open_gather(const EVP_AEAD_CTX * ctx,uint8_t * out,const uint8_t * nonce,size_t nonce_len,const uint8_t * in,size_t in_len,const uint8_t * in_tag,size_t in_tag_len,const uint8_t * ad,size_t ad_len)203 static int aead_aes_eax_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
204                                     const uint8_t *nonce, size_t nonce_len,
205                                     const uint8_t *in, size_t in_len,
206                                     const uint8_t *in_tag, size_t in_tag_len,
207                                     const uint8_t *ad, size_t ad_len) {
208   const uint64_t ad_len_64 = ad_len;
209   if (ad_len_64 >= (UINT64_C(1) << 61)) {
210     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
211     return 0;
212   }
213 
214   const uint64_t in_len_64 = in_len;
215   if (in_tag_len != EVP_AEAD_AES_EAX_TAG_LEN ||
216       in_len_64 > (UINT64_C(1) << 36) + AES_BLOCK_SIZE) {
217     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
218     return 0;
219   }
220 
221   if (nonce_len != 12 && nonce_len != 16) {
222     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
223     return 0;
224   }
225 
226   const struct aead_aes_eax_ctx *aes_ctx =
227       (struct aead_aes_eax_ctx *)&ctx->state;
228 
229   // N <- OMAC(0 || nonce)
230   uint8_t n[AES_BLOCK_SIZE];
231   omac_with_tag(aes_ctx, n, nonce, nonce_len, /*tag=*/0);
232   // H <- OMAC(1 || ad)
233   uint8_t h[AES_BLOCK_SIZE];
234   omac_with_tag(aes_ctx, h, ad, ad_len, /*tag=*/1);
235 
236   // MAC <- OMAC(2 || C)
237   uint8_t mac[AES_BLOCK_SIZE];
238   omac_with_tag(aes_ctx, mac, in, in_len, /*tag=*/2);
239   // MAC <- N ^ C ^ H
240   CRYPTO_xor16(mac, n, mac);
241   CRYPTO_xor16(mac, h, mac);
242 
243   if (CRYPTO_memcmp(mac, in_tag, in_tag_len) != 0) {
244     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
245     return 0;
246   }
247 
248   // M <- CTR^{N}_{K}(C)
249   aes_ctr(aes_ctx, out, n, in, in_len);
250   return 1;
251 }
252 
253 static const EVP_AEAD aead_aes_128_eax = {
254     16,                        // AES key size
255     16,                        // nonce length
256     EVP_AEAD_AES_EAX_TAG_LEN,  // overhead
257     EVP_AEAD_AES_EAX_TAG_LEN,  // max tag length
258     0,                         // seal_scatter_supports_extra_in
259 
260     aead_aes_eax_init,
261     NULL,  // init_with_direction
262     aead_aes_eax_cleanup,
263     NULL,  // open
264     aead_aes_eax_seal_scatter,
265     aead_aes_eax_open_gather,
266     NULL,  // get_iv
267     NULL,  // tag_len
268 };
269 
270 static const EVP_AEAD aead_aes_256_eax = {
271     32,                        // AES key size
272     16,                        // nonce length
273     EVP_AEAD_AES_EAX_TAG_LEN,  // overhead
274     EVP_AEAD_AES_EAX_TAG_LEN,  // max tag length
275     0,                         // seal_scatter_supports_extra_in
276 
277     aead_aes_eax_init,
278     NULL,  // init_with_direction
279     aead_aes_eax_cleanup,
280     NULL,  // open
281     aead_aes_eax_seal_scatter,
282     aead_aes_eax_open_gather,
283     NULL,  // get_iv
284     NULL,  // tag_len
285 };
286 
EVP_aead_aes_128_eax(void)287 const EVP_AEAD *EVP_aead_aes_128_eax(void) { return &aead_aes_128_eax; }
288 
EVP_aead_aes_256_eax(void)289 const EVP_AEAD *EVP_aead_aes_256_eax(void) { return &aead_aes_256_eax; }
290