| 1 | /* Copyright (c) (2015-2019,2021,2022) Apple Inc. All rights reserved. |
| 2 | * |
| 3 | * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which |
| 4 | * is contained in the License.txt file distributed with corecrypto) and only to |
| 5 | * people who accept that license. IMPORTANT: Any license rights granted to you by |
| 6 | * Apple Inc. (if any) are limited to internal use within your organization only on |
| 7 | * devices and computers you own or control, for the sole purpose of verifying the |
| 8 | * security characteristics and correct functioning of the Apple Software. You may |
| 9 | * not, directly or indirectly, redistribute the Apple Software or any portions thereof. |
| 10 | * |
| 11 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
| 12 | * |
| 13 | * This file contains Original Code and/or Modifications of Original Code |
| 14 | * as defined in and that are subject to the Apple Public Source License |
| 15 | * Version 2.0 (the 'License'). You may not use this file except in |
| 16 | * compliance with the License. The rights granted to you under the License |
| 17 | * may not be used to create, or enable the creation or redistribution of, |
| 18 | * unlawful or unlicensed copies of an Apple operating system, or to |
| 19 | * circumvent, violate, or enable the circumvention or violation of, any |
| 20 | * terms of an Apple operating system software license agreement. |
| 21 | * |
| 22 | * Please obtain a copy of the License at |
| 23 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
| 24 | * |
| 25 | * The Original Code and all software distributed under the License are |
| 26 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| 27 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| 28 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| 29 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
| 30 | * Please see the License for the specific language governing rights and |
| 31 | * limitations under the License. |
| 32 | * |
| 33 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
| 34 | */ |
| 35 | |
| 36 | #include "cc_internal.h" |
| 37 | #include "cc_macros.h" |
| 38 | #include "fipspost_trace.h" |
| 39 | #include "ccmode_gcm_internal.h" |
| 40 | #include <corecrypto/ccmode.h> |
| 41 | |
| 42 | size_t |
| 43 | ccgcm_context_size(const struct ccmode_gcm *mode) |
| 44 | { |
| 45 | CC_ENSURE_DIT_ENABLED |
| 46 | |
| 47 | return mode->size; |
| 48 | } |
| 49 | |
| 50 | size_t |
| 51 | ccgcm_block_size(const struct ccmode_gcm *mode) |
| 52 | { |
| 53 | CC_ENSURE_DIT_ENABLED |
| 54 | |
| 55 | return mode->block_size; |
| 56 | } |
| 57 | |
| 58 | int |
| 59 | ccgcm_init(const struct ccmode_gcm *mode, |
| 60 | ccgcm_ctx *ctx, |
| 61 | size_t key_nbytes, |
| 62 | const void *cc_sized_by(key_nbytes)key) |
| 63 | { |
| 64 | CC_ENSURE_DIT_ENABLED |
| 65 | |
| 66 | return mode->init(mode, ctx, key_nbytes, key); |
| 67 | } |
| 68 | |
| 69 | int |
| 70 | ccgcm_init_with_iv(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, |
| 71 | size_t key_nbytes, const void *key, |
| 72 | const void *iv) |
| 73 | { |
| 74 | CC_ENSURE_DIT_ENABLED |
| 75 | |
| 76 | int rc; |
| 77 | |
| 78 | rc = ccgcm_init(mode, ctx, key_nbytes, key); |
| 79 | if (rc == 0) { |
| 80 | rc = ccgcm_set_iv(mode, ctx, CCGCM_IV_NBYTES, iv); |
| 81 | } |
| 82 | if (rc == 0) { |
| 83 | _CCMODE_GCM_KEY(ctx)->flags |= CCGCM_FLAGS_INIT_WITH_IV; |
| 84 | } |
| 85 | return rc; |
| 86 | } |
| 87 | |
| 88 | int |
| 89 | ccgcm_set_iv(const struct ccmode_gcm *mode, |
| 90 | ccgcm_ctx *ctx, |
| 91 | size_t iv_nbytes, |
| 92 | const void *cc_sized_by(iv_nbytes)iv) |
| 93 | { |
| 94 | CC_ENSURE_DIT_ENABLED |
| 95 | |
| 96 | return mode->set_iv(ctx, iv_nbytes, iv); |
| 97 | } |
| 98 | |
| 99 | int |
| 100 | ccgcm_inc_iv(CC_UNUSED const struct ccmode_gcm *mode, ccgcm_ctx *ctx, void *iv) |
| 101 | { |
| 102 | CC_ENSURE_DIT_ENABLED |
| 103 | |
| 104 | uint8_t *Y0 = CCMODE_GCM_KEY_Y_0(ctx); |
| 105 | |
| 106 | cc_require(_CCMODE_GCM_KEY(ctx)->state == CCMODE_GCM_STATE_IV, errOut); |
| 107 | cc_require(_CCMODE_GCM_KEY(ctx)->flags & CCGCM_FLAGS_INIT_WITH_IV, errOut); |
| 108 | |
| 109 | inc_uint(buf: Y0 + 4, nbytes: 8); |
| 110 | cc_memcpy(iv, Y0, CCGCM_IV_NBYTES); |
| 111 | cc_memcpy(CCMODE_GCM_KEY_Y(ctx), Y0, CCGCM_BLOCK_NBYTES); |
| 112 | ccmode_gcm_update_pad(key: ctx); |
| 113 | |
| 114 | _CCMODE_GCM_KEY(ctx)->state = CCMODE_GCM_STATE_AAD; |
| 115 | |
| 116 | return 0; |
| 117 | |
| 118 | errOut: |
| 119 | return CCMODE_INVALID_CALL_SEQUENCE; |
| 120 | } |
| 121 | |
| 122 | int |
| 123 | ccgcm_aad(const struct ccmode_gcm *mode, |
| 124 | ccgcm_ctx *ctx, |
| 125 | size_t nbytes, |
| 126 | const void *cc_sized_by(nbytes)additional_data) |
| 127 | { |
| 128 | CC_ENSURE_DIT_ENABLED |
| 129 | |
| 130 | return mode->gmac(ctx, nbytes, additional_data); |
| 131 | } |
| 132 | |
| 133 | int |
| 134 | ccgcm_gmac(const struct ccmode_gcm *mode, |
| 135 | ccgcm_ctx *ctx, |
| 136 | size_t nbytes, |
| 137 | const void *cc_sized_by(nbytes)in) |
| 138 | { |
| 139 | CC_ENSURE_DIT_ENABLED |
| 140 | |
| 141 | return mode->gmac(ctx, nbytes, in); |
| 142 | } |
| 143 | |
| 144 | int |
| 145 | ccgcm_update(const struct ccmode_gcm *mode, |
| 146 | ccgcm_ctx *ctx, |
| 147 | size_t nbytes, |
| 148 | const void *cc_sized_by(nbytes)in, |
| 149 | void *cc_sized_by(nbytes)out) |
| 150 | { |
| 151 | CC_ENSURE_DIT_ENABLED |
| 152 | |
| 153 | return mode->gcm(ctx, nbytes, in, out); |
| 154 | } |
| 155 | |
| 156 | int |
| 157 | ccgcm_finalize(const struct ccmode_gcm *mode, |
| 158 | ccgcm_ctx *ctx, |
| 159 | size_t tag_nbytes, |
| 160 | void *cc_sized_by(tag_nbytes)tag) |
| 161 | { |
| 162 | CC_ENSURE_DIT_ENABLED |
| 163 | |
| 164 | return mode->finalize(ctx, tag_nbytes, tag); |
| 165 | } |
| 166 | |
| 167 | int |
| 168 | ccgcm_reset(const struct ccmode_gcm *mode, ccgcm_ctx *ctx) |
| 169 | { |
| 170 | CC_ENSURE_DIT_ENABLED |
| 171 | |
| 172 | return mode->reset(ctx); |
| 173 | } |
| 174 | |
| 175 | int |
| 176 | ccgcm_one_shot(const struct ccmode_gcm *mode, |
| 177 | size_t key_nbytes, const void *key, |
| 178 | size_t iv_nbytes, const void *iv, |
| 179 | size_t adata_nbytes, const void *adata, |
| 180 | size_t nbytes, const void *in, void *out, |
| 181 | size_t tag_nbytes, void *tag) |
| 182 | { |
| 183 | CC_ENSURE_DIT_ENABLED |
| 184 | |
| 185 | FIPSPOST_TRACE_EVENT; |
| 186 | |
| 187 | int rc = 0; |
| 188 | |
| 189 | ccgcm_ctx_decl(mode->size, ctx); |
| 190 | rc = ccgcm_init(mode, ctx, key_nbytes, key); cc_require(rc == 0, errOut); |
| 191 | rc = ccgcm_set_iv(mode, ctx, iv_nbytes, iv); cc_require(rc == 0, errOut); |
| 192 | rc = ccgcm_aad(mode, ctx, nbytes: adata_nbytes, additional_data: adata); cc_require(rc == 0, errOut); |
| 193 | rc = ccgcm_update(mode, ctx, nbytes, in, out); cc_require(rc == 0, errOut); |
| 194 | rc = ccgcm_finalize(mode, ctx, tag_nbytes, tag); cc_require(rc == 0, errOut); |
| 195 | |
| 196 | errOut: |
| 197 | ccgcm_ctx_clear(mode->size, ctx); |
| 198 | return rc; |
| 199 | } |
| 200 | |
| 201 | |
| 202 | //ccgcm_one_shot_legacy() is created because in the previous implementation of aes-gcm |
| 203 | //set_iv() could be skipped. |
| 204 | //In the new version of aes-gcm set_iv() cannot be skipped and IV length cannot |
| 205 | //be zero, as specified in FIPS. |
| 206 | //do not call ccgcm_one_shot_legacy() in any new application |
| 207 | int |
| 208 | ccgcm_set_iv_legacy(const struct ccmode_gcm *mode, ccgcm_ctx *key, size_t iv_nbytes, const void *iv) |
| 209 | { |
| 210 | CC_ENSURE_DIT_ENABLED |
| 211 | |
| 212 | int rc = -1; |
| 213 | |
| 214 | if (iv_nbytes == 0 || iv == NULL) { |
| 215 | /* must be in IV state */ |
| 216 | cc_require(_CCMODE_GCM_KEY(key)->state == CCMODE_GCM_STATE_IV, errOut); /* CRYPT_INVALID_ARG */ |
| 217 | |
| 218 | // this is the net effect of setting IV to the empty string |
| 219 | cc_clear(CCGCM_BLOCK_NBYTES, CCMODE_GCM_KEY_Y(key)); |
| 220 | ccmode_gcm_update_pad(key); |
| 221 | cc_clear(CCGCM_BLOCK_NBYTES, CCMODE_GCM_KEY_Y_0(key)); |
| 222 | |
| 223 | _CCMODE_GCM_KEY(key)->state = CCMODE_GCM_STATE_AAD; |
| 224 | rc = 0; |
| 225 | } else { |
| 226 | rc = ccgcm_set_iv(mode, ctx: key, iv_nbytes, iv); |
| 227 | } |
| 228 | |
| 229 | errOut: |
| 230 | return rc; |
| 231 | } |
| 232 | |
| 233 | int |
| 234 | ccgcm_one_shot_legacy(const struct ccmode_gcm *mode, |
| 235 | size_t key_nbytes, const void *key, |
| 236 | size_t iv_nbytes, const void *iv, |
| 237 | size_t adata_nbytes, const void *adata, |
| 238 | size_t nbytes, const void *in, void *out, |
| 239 | size_t tag_nbytes, void *tag) |
| 240 | { |
| 241 | CC_ENSURE_DIT_ENABLED |
| 242 | |
| 243 | int rc = 0; |
| 244 | |
| 245 | ccgcm_ctx_decl(mode->size, ctx); |
| 246 | rc = ccgcm_init(mode, ctx, key_nbytes, key); cc_require(rc == 0, errOut); |
| 247 | rc = ccgcm_set_iv_legacy(mode, key: ctx, iv_nbytes, iv); cc_require(rc == 0, errOut); |
| 248 | rc = ccgcm_aad(mode, ctx, nbytes: adata_nbytes, additional_data: adata); cc_require(rc == 0, errOut); |
| 249 | rc = ccgcm_update(mode, ctx, nbytes, in, out); cc_require(rc == 0, errOut); |
| 250 | rc = ccgcm_finalize(mode, ctx, tag_nbytes, tag); cc_require(rc == 0, errOut); |
| 251 | |
| 252 | errOut: |
| 253 | ccgcm_ctx_clear(mode->size, ctx); |
| 254 | return rc; |
| 255 | } |
| 256 | |
| 257 | void |
| 258 | inc_uint(uint8_t *buf, size_t nbytes) |
| 259 | { |
| 260 | for (size_t i = 1; i <= nbytes; i += 1) { |
| 261 | size_t j = nbytes - i; |
| 262 | buf[j] = (uint8_t)(buf[j] + 1); |
| 263 | if (buf[j] > 0) { |
| 264 | return; |
| 265 | } |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | void |
| 270 | ccmode_gcm_update_pad(ccgcm_ctx *key) |
| 271 | { |
| 272 | inc_uint(CCMODE_GCM_KEY_Y(key) + 12, nbytes: 4); |
| 273 | CCMODE_GCM_KEY_ECB(key)->ecb(CCMODE_GCM_KEY_ECB_KEY(key), 1, |
| 274 | CCMODE_GCM_KEY_Y(key), |
| 275 | CCMODE_GCM_KEY_PAD(key)); |
| 276 | } |
| 277 | |
| 278 | void |
| 279 | ccmode_gcm_aad_finalize(ccgcm_ctx *key) |
| 280 | { |
| 281 | if (_CCMODE_GCM_KEY(key)->state == CCMODE_GCM_STATE_AAD) { |
| 282 | if (_CCMODE_GCM_KEY(key)->aad_nbytes % CCGCM_BLOCK_NBYTES > 0) { |
| 283 | ccmode_gcm_mult_h(key, CCMODE_GCM_KEY_X(key)); |
| 284 | } |
| 285 | _CCMODE_GCM_KEY(key)->state = CCMODE_GCM_STATE_TEXT; |
| 286 | } |
| 287 | } |
| 288 | |