blob: 3e18659358f493681864512dded6af39e7daa2c9 [file] [log] [blame]
Robert Sloanab8b8882018-03-26 11:39:51 -07001/* Copyright (c) 2018, 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
19#include <openssl/cipher.h>
20#include <openssl/err.h>
21#include <openssl/mem.h>
22
23#include "../fipsmodule/cipher/internal.h"
24
25
26#define EVP_AEAD_AES_CCM_MAX_TAG_LEN 16
27
28struct aead_aes_ccm_ctx {
29 union {
30 double align;
31 AES_KEY ks;
32 } ks;
33 CCM128_CONTEXT ccm;
34};
35
Robert Sloanc9abfe42018-11-26 12:19:07 -080036OPENSSL_STATIC_ASSERT(sizeof(((EVP_AEAD_CTX *)NULL)->state) >=
37 sizeof(struct aead_aes_ccm_ctx),
38 "AEAD state is too small");
Robert Sloan5bdaadb2018-10-30 16:00:26 -070039#if defined(__GNUC__) || defined(__clang__)
Robert Sloanc9abfe42018-11-26 12:19:07 -080040OPENSSL_STATIC_ASSERT(alignof(union evp_aead_ctx_st_state) >=
41 alignof(struct aead_aes_ccm_ctx),
42 "AEAD state has insufficient alignment");
Robert Sloan5bdaadb2018-10-30 16:00:26 -070043#endif
44
Robert Sloanab8b8882018-03-26 11:39:51 -070045static int aead_aes_ccm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
46 size_t key_len, size_t tag_len, unsigned M,
47 unsigned L) {
48 assert(M == EVP_AEAD_max_overhead(ctx->aead));
49 assert(M == EVP_AEAD_max_tag_len(ctx->aead));
50 assert(15 - L == EVP_AEAD_nonce_length(ctx->aead));
51
52 if (key_len != EVP_AEAD_key_length(ctx->aead)) {
53 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
54 return 0; // EVP_AEAD_CTX_init should catch this.
55 }
56
57 if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
58 tag_len = M;
59 }
60
61 if (tag_len != M) {
62 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
63 return 0;
64 }
65
Robert Sloan5bdaadb2018-10-30 16:00:26 -070066 struct aead_aes_ccm_ctx *ccm_ctx = (struct aead_aes_ccm_ctx *)&ctx->state;
Robert Sloanab8b8882018-03-26 11:39:51 -070067
68 block128_f block;
69 ctr128_f ctr = aes_ctr_set_key(&ccm_ctx->ks.ks, NULL, &block, key, key_len);
70 ctx->tag_len = tag_len;
71 if (!CRYPTO_ccm128_init(&ccm_ctx->ccm, &ccm_ctx->ks.ks, block, ctr, M, L)) {
72 OPENSSL_PUT_ERROR(CIPHER, ERR_R_INTERNAL_ERROR);
Robert Sloanab8b8882018-03-26 11:39:51 -070073 return 0;
74 }
75
Robert Sloanab8b8882018-03-26 11:39:51 -070076 return 1;
77}
78
Robert Sloan5bdaadb2018-10-30 16:00:26 -070079static void aead_aes_ccm_cleanup(EVP_AEAD_CTX *ctx) {}
Robert Sloanab8b8882018-03-26 11:39:51 -070080
81static int aead_aes_ccm_seal_scatter(
82 const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
83 size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
84 size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
85 size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
Robert Sloan5bdaadb2018-10-30 16:00:26 -070086 const struct aead_aes_ccm_ctx *ccm_ctx =
87 (struct aead_aes_ccm_ctx *)&ctx->state;
Robert Sloanab8b8882018-03-26 11:39:51 -070088
89 if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
90 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
91 return 0;
92 }
93
94 if (max_out_tag_len < ctx->tag_len) {
95 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
96 return 0;
97 }
98
99 if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
100 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
101 return 0;
102 }
103
104 if (!CRYPTO_ccm128_encrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, out_tag,
105 ctx->tag_len, nonce, nonce_len, in, in_len, ad,
106 ad_len)) {
107 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
108 return 0;
109 }
110
111 *out_tag_len = ctx->tag_len;
112 return 1;
113}
114
115static int aead_aes_ccm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
116 const uint8_t *nonce, size_t nonce_len,
117 const uint8_t *in, size_t in_len,
118 const uint8_t *in_tag, size_t in_tag_len,
119 const uint8_t *ad, size_t ad_len) {
Robert Sloan5bdaadb2018-10-30 16:00:26 -0700120 const struct aead_aes_ccm_ctx *ccm_ctx =
121 (struct aead_aes_ccm_ctx *)&ctx->state;
Robert Sloanab8b8882018-03-26 11:39:51 -0700122
123 if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
124 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
125 return 0;
126 }
127
128 if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
129 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
130 return 0;
131 }
132
133 if (in_tag_len != ctx->tag_len) {
134 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
135 return 0;
136 }
137
138 uint8_t tag[EVP_AEAD_AES_CCM_MAX_TAG_LEN];
139 assert(ctx->tag_len <= EVP_AEAD_AES_CCM_MAX_TAG_LEN);
140 if (!CRYPTO_ccm128_decrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, tag,
141 ctx->tag_len, nonce, nonce_len, in, in_len, ad,
142 ad_len)) {
143 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
144 return 0;
145 }
146
147 if (CRYPTO_memcmp(tag, in_tag, ctx->tag_len) != 0) {
148 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
149 return 0;
150 }
151
152 return 1;
153}
154
155static int aead_aes_ccm_bluetooth_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
156 size_t key_len, size_t tag_len) {
157 return aead_aes_ccm_init(ctx, key, key_len, tag_len, 4, 2);
158}
159
160static const EVP_AEAD aead_aes_128_ccm_bluetooth = {
161 16, // key length (AES-128)
162 13, // nonce length
163 4, // overhead
164 4, // max tag length
165 0, // seal_scatter_supports_extra_in
166
167 aead_aes_ccm_bluetooth_init,
168 NULL /* init_with_direction */,
169 aead_aes_ccm_cleanup,
170 NULL /* open */,
171 aead_aes_ccm_seal_scatter,
172 aead_aes_ccm_open_gather,
173 NULL /* get_iv */,
174 NULL /* tag_len */,
175};
176
177const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void) {
178 return &aead_aes_128_ccm_bluetooth;
179}
180
181static int aead_aes_ccm_bluetooth_8_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
182 size_t key_len, size_t tag_len) {
183 return aead_aes_ccm_init(ctx, key, key_len, tag_len, 8, 2);
184}
185
186static const EVP_AEAD aead_aes_128_ccm_bluetooth_8 = {
187 16, // key length (AES-128)
188 13, // nonce length
189 8, // overhead
190 8, // max tag length
191 0, // seal_scatter_supports_extra_in
192
193 aead_aes_ccm_bluetooth_8_init,
194 NULL /* init_with_direction */,
195 aead_aes_ccm_cleanup,
196 NULL /* open */,
197 aead_aes_ccm_seal_scatter,
198 aead_aes_ccm_open_gather,
199 NULL /* get_iv */,
200 NULL /* tag_len */,
201};
202
203const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth_8(void) {
204 return &aead_aes_128_ccm_bluetooth_8;
205}