1/* Copyright (c) 2014, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15#include <openssl/aead.h> 16 17#include <assert.h> 18#include <string.h> 19 20#include <openssl/cipher.h> 21#include <openssl/err.h> 22#include <openssl/mem.h> 23 24#include "internal.h" 25#include "../../internal.h" 26 27 28size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } 29 30size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } 31 32size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } 33 34size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } 35 36void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) { 37 OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX)); 38} 39 40EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key, 41 size_t key_len, size_t tag_len) { 42 EVP_AEAD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_AEAD_CTX)); 43 EVP_AEAD_CTX_zero(ctx); 44 45 if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL)) { 46 return ctx; 47 } 48 49 EVP_AEAD_CTX_free(ctx); 50 return NULL; 51} 52 53void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) { 54 EVP_AEAD_CTX_cleanup(ctx); 55 OPENSSL_free(ctx); 56} 57 58int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, 59 const uint8_t *key, size_t key_len, size_t tag_len, 60 ENGINE *impl) { 61 if (!aead->init) { 62 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); 63 ctx->aead = NULL; 64 return 0; 65 } 66 return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, 67 evp_aead_open); 68} 69 70int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, 71 const uint8_t *key, size_t key_len, 72 size_t tag_len, 73 enum evp_aead_direction_t dir) { 74 if (key_len != aead->key_len) { 75 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); 76 ctx->aead = NULL; 77 return 0; 78 } 79 80 ctx->aead = aead; 81 82 int ok; 83 if (aead->init) { 84 ok = aead->init(ctx, key, key_len, tag_len); 85 } else { 86 ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); 87 } 88 89 if (!ok) { 90 ctx->aead = NULL; 91 } 92 93 return ok; 94} 95 96void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { 97 if (ctx->aead == NULL) { 98 return; 99 } 100 ctx->aead->cleanup(ctx); 101 ctx->aead = NULL; 102} 103 104// check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If 105// |in| and |out| alias, we require that |in| == |out|. 106static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out, 107 size_t out_len) { 108 if (!buffers_alias(in, in_len, out, out_len)) { 109 return 1; 110 } 111 112 return in == out; 113} 114 115int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, 116 size_t max_out_len, const uint8_t *nonce, 117 size_t nonce_len, const uint8_t *in, size_t in_len, 118 const uint8_t *ad, size_t ad_len) { 119 if (in_len + ctx->aead->overhead < in_len /* overflow */) { 120 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); 121 goto error; 122 } 123 124 if (max_out_len < in_len) { 125 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); 126 goto error; 127 } 128 129 if (!check_alias(in, in_len, out, max_out_len)) { 130 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 131 goto error; 132 } 133 134 size_t out_tag_len; 135 if (ctx->aead->seal_scatter(ctx, out, out + in_len, &out_tag_len, 136 max_out_len - in_len, nonce, nonce_len, in, 137 in_len, NULL, 0, ad, ad_len)) { 138 *out_len = in_len + out_tag_len; 139 return 1; 140 } 141 142error: 143 // In the event of an error, clear the output buffer so that a caller 144 // that doesn't check the return value doesn't send raw data. 145 OPENSSL_memset(out, 0, max_out_len); 146 *out_len = 0; 147 return 0; 148} 149 150int EVP_AEAD_CTX_seal_scatter( 151 const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag, size_t 152 *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce, size_t 153 nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in, 154 size_t extra_in_len, const uint8_t *ad, size_t ad_len) { 155 // |in| and |out| may alias exactly, |out_tag| may not alias. 156 if (!check_alias(in, in_len, out, in_len) || 157 buffers_alias(out, in_len, out_tag, max_out_tag_len) || 158 buffers_alias(in, in_len, out_tag, max_out_tag_len)) { 159 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 160 goto error; 161 } 162 163 if (!ctx->aead->seal_scatter_supports_extra_in && extra_in_len) { 164 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); 165 goto error; 166 } 167 168 if (ctx->aead->seal_scatter(ctx, out, out_tag, out_tag_len, max_out_tag_len, 169 nonce, nonce_len, in, in_len, extra_in, 170 extra_in_len, ad, ad_len)) { 171 return 1; 172 } 173 174error: 175 // In the event of an error, clear the output buffer so that a caller 176 // that doesn't check the return value doesn't send raw data. 177 OPENSSL_memset(out, 0, in_len); 178 OPENSSL_memset(out_tag, 0, max_out_tag_len); 179 *out_tag_len = 0; 180 return 0; 181} 182 183int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, 184 size_t max_out_len, const uint8_t *nonce, 185 size_t nonce_len, const uint8_t *in, size_t in_len, 186 const uint8_t *ad, size_t ad_len) { 187 if (!check_alias(in, in_len, out, max_out_len)) { 188 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 189 goto error; 190 } 191 192 if (ctx->aead->open) { 193 if (!ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, 194 in_len, ad, ad_len)) { 195 goto error; 196 } 197 return 1; 198 } 199 200 // AEADs that use the default implementation of open() must set |tag_len| at 201 // initialization time. 202 assert(ctx->tag_len); 203 204 if (in_len < ctx->tag_len) { 205 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); 206 goto error; 207 } 208 209 size_t plaintext_len = in_len - ctx->tag_len; 210 if (max_out_len < plaintext_len) { 211 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); 212 goto error; 213 } 214 if (EVP_AEAD_CTX_open_gather(ctx, out, nonce, nonce_len, in, plaintext_len, 215 in + plaintext_len, ctx->tag_len, ad, ad_len)) { 216 *out_len = plaintext_len; 217 return 1; 218 } 219 220error: 221 // In the event of an error, clear the output buffer so that a caller 222 // that doesn't check the return value doesn't try and process bad 223 // data. 224 OPENSSL_memset(out, 0, max_out_len); 225 *out_len = 0; 226 return 0; 227} 228 229int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out, 230 const uint8_t *nonce, size_t nonce_len, 231 const uint8_t *in, size_t in_len, 232 const uint8_t *in_tag, size_t in_tag_len, 233 const uint8_t *ad, size_t ad_len) { 234 if (!check_alias(in, in_len, out, in_len)) { 235 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 236 goto error; 237 } 238 239 if (!ctx->aead->open_gather) { 240 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); 241 goto error; 242 } 243 244 if (ctx->aead->open_gather(ctx, out, nonce, nonce_len, in, in_len, in_tag, 245 in_tag_len, ad, ad_len)) { 246 return 1; 247 } 248 249error: 250 // In the event of an error, clear the output buffer so that a caller 251 // that doesn't check the return value doesn't try and process bad 252 // data. 253 OPENSSL_memset(out, 0, in_len); 254 return 0; 255} 256 257const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; } 258 259int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, 260 size_t *out_len) { 261 if (ctx->aead->get_iv == NULL) { 262 return 0; 263 } 264 265 return ctx->aead->get_iv(ctx, out_iv, out_len); 266} 267 268int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len, 269 const size_t in_len, const size_t extra_in_len) { 270 assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len); 271 272 if (ctx->aead->tag_len) { 273 *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len); 274 return 1; 275 } 276 277 if (extra_in_len + ctx->tag_len < extra_in_len) { 278 OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW); 279 *out_tag_len = 0; 280 return 0; 281 } 282 *out_tag_len = extra_in_len + ctx->tag_len; 283 return 1; 284} 285