Coverage Report

Created: 2026-08-08 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/aes/aes.cc.inc
Line
Count
Source
1
// Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
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 <assert.h>
16
17
#include "../bcm_interface.h"
18
#include "internal.h"
19
20
21
using namespace bssl;
22
23
// Be aware that different sets of AES functions use incompatible key
24
// representations, varying in format of the key schedule, the `AES_KEY.rounds`
25
// value, or both. Therefore they cannot mix. Also, on AArch64, the plain-C
26
// code, above, is incompatible with the `aes_hw_*` functions.
27
28
bcm_infallible bssl::BCM_aes_encrypt(const uint8_t *in, uint8_t *out,
29
6.50M
                                     const AES_KEY *key) {
30
6.50M
  if (hwaes_capable()) {
31
6.50M
    aes_hw_encrypt(in, out, key);
32
6.50M
  } else if (vpaes_capable()) {
33
0
    vpaes_encrypt(in, out, key);
34
0
  } else {
35
0
    aes_nohw_encrypt(in, out, key);
36
0
  }
37
6.50M
  return bcm_infallible::not_approved;
38
6.50M
}
39
40
bcm_infallible bssl::BCM_aes_decrypt(const uint8_t *in, uint8_t *out,
41
0
                                     const AES_KEY *key) {
42
0
  if (hwaes_capable()) {
43
0
    aes_hw_decrypt(in, out, key);
44
0
  } else if (vpaes_capable()) {
45
0
    vpaes_decrypt(in, out, key);
46
0
  } else {
47
0
    aes_nohw_decrypt(in, out, key);
48
0
  }
49
0
  return bcm_infallible::not_approved;
50
0
}
51
52
bcm_status bssl::BCM_aes_set_encrypt_key(const uint8_t *key, unsigned bits,
53
867k
                                         AES_KEY *aeskey) {
54
867k
  int ret = -1;
55
867k
  if (hwaes_capable()) {
56
867k
    ret = aes_hw_set_encrypt_key(key, bits, aeskey);
57
867k
  } else if (vpaes_capable()) {
58
0
    ret = vpaes_set_encrypt_key(key, bits, aeskey);
59
0
  } else {
60
0
    ret = aes_nohw_set_encrypt_key(key, bits, aeskey);
61
0
  }
62
867k
  if (ret < 0) {
63
0
    return bcm_status::failure;
64
0
  }
65
867k
  BSSL_CHECK(ret == 0);
66
867k
  return bcm_status::not_approved;
67
867k
}
68
69
bcm_status bssl::BCM_aes_set_decrypt_key(const uint8_t *key, unsigned bits,
70
0
                                         AES_KEY *aeskey) {
71
0
  int ret = -1;
72
0
  if (hwaes_capable()) {
73
0
    ret = aes_hw_set_decrypt_key(key, bits, aeskey);
74
0
  } else if (vpaes_capable()) {
75
0
    ret = vpaes_set_decrypt_key(key, bits, aeskey);
76
0
  } else {
77
0
    ret = aes_nohw_set_decrypt_key(key, bits, aeskey);
78
0
  }
79
0
  if (ret < 0) {
80
0
    return bcm_status::failure;
81
0
  }
82
0
  BSSL_CHECK(ret == 0);
83
0
  return bcm_status::not_approved;
84
0
}
85
86
#if defined(HWAES) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
87
// On x86 and x86_64, `aes_hw_set_decrypt_key`, we implement
88
// `aes_hw_encrypt_key_to_decrypt_key` in assembly and rely on C code to combine
89
// the operations.
90
int bssl::aes_hw_set_decrypt_key(const uint8_t *user_key, int bits,
91
13.1k
                                 AES_KEY *key) {
92
13.1k
  int ret = aes_hw_set_encrypt_key(user_key, bits, key);
93
13.1k
  if (ret == 0) {
94
13.1k
    aes_hw_encrypt_key_to_decrypt_key(key);
95
13.1k
  }
96
13.1k
  return ret;
97
13.1k
}
98
99
int bssl::aes_hw_set_encrypt_key(const uint8_t *user_key, int bits,
100
1.85M
                                 AES_KEY *key) {
101
1.85M
  if (aes_hw_set_encrypt_key_alt_preferred()) {
102
1.85M
    return aes_hw_set_encrypt_key_alt(user_key, bits, key);
103
1.85M
  } else {
104
0
    return aes_hw_set_encrypt_key_base(user_key, bits, key);
105
0
  }
106
1.85M
}
107
#endif
108
109
#if defined(VPAES) && defined(OPENSSL_X86)
110
// On x86, there is no `vpaes_ctr32_encrypt_blocks`, so we implement it
111
// ourselves. This avoids all callers needing to account for a missing function.
112
void bssl::vpaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out,
113
                                      size_t blocks, const AES_KEY *key,
114
                                      const uint8_t iv[16]) {
115
  uint32_t ctr = CRYPTO_load_u32_be(iv + 12);
116
  uint8_t iv_buf[16], enc[16];
117
  OPENSSL_memcpy(iv_buf, iv, 12);
118
  for (size_t i = 0; i < blocks; i++) {
119
    CRYPTO_store_u32_be(iv_buf + 12, ctr);
120
    vpaes_encrypt(iv_buf, enc, key);
121
    CRYPTO_xor16(out, in, enc);
122
    ctr++;
123
    in += 16;
124
    out += 16;
125
  }
126
}
127
#endif
128
129
#if defined(BSAES)
130
void bssl::vpaes_ctr32_encrypt_blocks_with_bsaes(const uint8_t *in,
131
                                                 uint8_t *out, size_t blocks,
132
                                                 const AES_KEY *key,
133
                                                 const uint8_t ivec[16]) {
134
  // `bsaes_ctr32_encrypt_blocks` is faster than `vpaes_ctr32_encrypt_blocks`,
135
  // but it takes at least one full 8-block batch to amortize the conversion.
136
  if (blocks < 8) {
137
    vpaes_ctr32_encrypt_blocks(in, out, blocks, key, ivec);
138
    return;
139
  }
140
141
  size_t bsaes_blocks = blocks;
142
  if (bsaes_blocks % 8 < 6) {
143
    // `bsaes_ctr32_encrypt_blocks` internally works in 8-block batches. If the
144
    // final batch is too small (under six blocks), it is faster to loop over
145
    // `vpaes_encrypt`. Round `bsaes_blocks` down to a multiple of 8.
146
    bsaes_blocks -= bsaes_blocks % 8;
147
  }
148
149
  AES_KEY bsaes;
150
  vpaes_encrypt_key_to_bsaes(&bsaes, key);
151
  bsaes_ctr32_encrypt_blocks(in, out, bsaes_blocks, &bsaes, ivec);
152
  OPENSSL_cleanse(&bsaes, sizeof(bsaes));
153
154
  in += 16 * bsaes_blocks;
155
  out += 16 * bsaes_blocks;
156
  blocks -= bsaes_blocks;
157
158
  uint8_t new_ivec[16];
159
  memcpy(new_ivec, ivec, 12);
160
  uint32_t ctr = CRYPTO_load_u32_be(ivec + 12) + bsaes_blocks;
161
  CRYPTO_store_u32_be(new_ivec + 12, ctr);
162
163
  // Finish any remaining blocks with `vpaes_ctr32_encrypt_blocks`.
164
  vpaes_ctr32_encrypt_blocks(in, out, blocks, key, new_ivec);
165
}
166
#endif  // BSAES
167
168
ctr128_f bssl::aes_ctr_set_key(AES_KEY *aes_key, int *out_is_hwaes,
169
                               block128_f *out_block, const uint8_t *key,
170
955k
                               size_t key_bytes) {
171
  // This function assumes the key length was previously validated.
172
955k
  assert(key_bytes == 128 / 8 || key_bytes == 192 / 8 || key_bytes == 256 / 8);
173
955k
  if (hwaes_capable()) {
174
955k
    aes_hw_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
175
955k
    if (out_is_hwaes) {
176
88.1k
      *out_is_hwaes = 1;
177
88.1k
    }
178
955k
    if (out_block) {
179
955k
      *out_block = aes_hw_encrypt;
180
955k
    }
181
955k
    return aes_hw_ctr32_encrypt_blocks;
182
955k
  }
183
184
0
  if (vpaes_capable()) {
185
0
    vpaes_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
186
0
    if (out_block) {
187
0
      *out_block = vpaes_encrypt;
188
0
    }
189
0
    if (out_is_hwaes) {
190
0
      *out_is_hwaes = 0;
191
0
    }
192
#if defined(BSAES)
193
    assert(bsaes_capable());
194
    return vpaes_ctr32_encrypt_blocks_with_bsaes;
195
#else
196
0
    return vpaes_ctr32_encrypt_blocks;
197
0
#endif
198
0
  }
199
200
0
  aes_nohw_set_encrypt_key(key, (int)key_bytes * 8, aes_key);
201
0
  if (out_is_hwaes) {
202
0
    *out_is_hwaes = 0;
203
0
  }
204
0
  if (out_block) {
205
0
    *out_block = aes_nohw_encrypt;
206
0
  }
207
0
  return aes_nohw_ctr32_encrypt_blocks;
208
0
}