1 /*
2 Copyright (c) 2021 Fraunhofer AISEC. See the COPYRIGHT
3 file at the top-level directory of this distribution.
4
5 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 option. This file may not be copied, modified, or distributed
9 except according to those terms.
10 */
11
12 #include "edhoc/buffer_sizes.h"
13
14 #include "edhoc/okm.h"
15 #include "edhoc/ciphertext.h"
16 #include "edhoc/signature_or_mac_msg.h"
17 #include "edhoc/plaintext.h"
18 #include "edhoc/associated_data_encode.h"
19 #include "edhoc/suites.h"
20 #include "edhoc/bstr_encode_decode.h"
21 #include "edhoc/int_encode_decode.h"
22
23 #include "common/crypto_wrapper.h"
24 #include "common/oscore_edhoc_error.h"
25 #include "common/memcpy_s.h"
26
27 /**
28 * @brief Xors two arrays.
29 *
30 * @param[in] in1 An input array.
31 * @param[in] in2 An input array.
32 * @param[out] out The result of the xor operation.
33 * @retval Ok or error code.
34 */
xor_arrays(const struct byte_array * in1,const struct byte_array * in2,struct byte_array * out)35 static inline enum err xor_arrays(const struct byte_array *in1,
36 const struct byte_array *in2,
37 struct byte_array *out)
38 {
39 if (in1->len != in2->len) {
40 return xor_error;
41 }
42 for (uint32_t i = 0; i < in1->len; i++) {
43 out->ptr[i] = in1->ptr[i] ^ in2->ptr[i];
44 }
45 return ok;
46 }
47
48 /**
49 * @brief Encrypts a plaintext or decrypts a ciphertext.
50 *
51 * @param ctxt CIPHERTEXT2, CIPHERTEXT3 or CIPHERTEXT4.
52 * @param op ENCRYPT or DECRYPT.
53 * @param[in] in Ciphertext or plaintext.
54 * @param[in] key The key used of encryption/decryption.
55 * @param[in] nonce AEAD nonce.
56 * @param[in] aad Additional authenticated data for AEAD.
57 * @param[out] out The result.
58 * @param[out] tag AEAD authentication tag.
59 * @return Ok or error code.
60 */
ciphertext_encrypt_decrypt(enum ciphertext ctxt,enum aes_operation op,const struct byte_array * in,const struct byte_array * key,struct byte_array * nonce,const struct byte_array * aad,struct byte_array * out,struct byte_array * tag)61 static enum err ciphertext_encrypt_decrypt(
62 enum ciphertext ctxt, enum aes_operation op,
63 const struct byte_array *in, const struct byte_array *key,
64 struct byte_array *nonce, const struct byte_array *aad,
65 struct byte_array *out, struct byte_array *tag)
66 {
67 if (ctxt == CIPHERTEXT2) {
68 xor_arrays(in, key, out);
69 } else {
70 PRINT_ARRAY("in", in->ptr, in->len);
71 TRY(aead(op, in, key, nonce, aad, out, tag));
72 }
73 return ok;
74 }
75
76 /**
77 * @brief Computes the key stream for ciphertext 2 and
78 * the key and IV for ciphertext 3 and 4.
79 *
80 * @param ctxt CIPHERTEXT2, CIPHERTEXT3 or CIPHERTEXT4.
81 * @param edhoc_hash The EDHOC hash algorithm.
82 * @param prk Pseudorandom key.
83 * @param th Transcript hash.
84 * @param[out] key The generated key/key stream.
85 * @param[out] iv The generated iv.
86 * @return Ok or error code.
87 */
key_gen(enum ciphertext ctxt,enum hash_alg edhoc_hash,struct byte_array * prk,struct byte_array * th,struct byte_array * key,struct byte_array * iv)88 static enum err key_gen(enum ciphertext ctxt, enum hash_alg edhoc_hash,
89 struct byte_array *prk, struct byte_array *th,
90 struct byte_array *key, struct byte_array *iv)
91 {
92 switch (ctxt) {
93 case CIPHERTEXT2:
94 TRY(edhoc_kdf(edhoc_hash, prk, KEYSTREAM_2, th, key));
95 PRINT_ARRAY("KEYSTREAM_2", key->ptr, key->len);
96 break;
97
98 case CIPHERTEXT3:
99 TRY(edhoc_kdf(edhoc_hash, prk, K_3, th, key));
100
101 PRINT_ARRAY("K_3", key->ptr, key->len);
102
103 TRY(edhoc_kdf(edhoc_hash, prk, IV_3, th, iv));
104 PRINT_ARRAY("IV_3", iv->ptr, iv->len);
105 break;
106
107 case CIPHERTEXT4:
108 PRINT_ARRAY("PRK_4e3m", prk->ptr, prk->len);
109 PRINT_ARRAY("TH_4", th->ptr, th->len);
110 TRY(edhoc_kdf(edhoc_hash, prk, K_4, th, key));
111 PRINT_ARRAY("K_4", key->ptr, key->len);
112 TRY(edhoc_kdf(edhoc_hash, prk, IV_4, th, iv));
113 PRINT_ARRAY("IV_4", iv->ptr, iv->len);
114 break;
115 }
116 return ok;
117 }
118
ciphertext_decrypt_split(enum ciphertext ctxt,struct suite * suite,struct byte_array * c_r,struct byte_array * id_cred,struct byte_array * sig_or_mac,struct byte_array * ead,struct byte_array * prk,struct byte_array * th,struct byte_array * ciphertext,struct byte_array * plaintext)119 enum err ciphertext_decrypt_split(
120 enum ciphertext ctxt, struct suite *suite, struct byte_array *c_r,
121 struct byte_array *id_cred, struct byte_array *sig_or_mac,
122 struct byte_array *ead, struct byte_array *prk, struct byte_array *th,
123 struct byte_array *ciphertext, struct byte_array *plaintext)
124 {
125 /*generate key and iv (no iv in for ciphertext 2)*/
126 uint32_t key_len;
127 if (ctxt == CIPHERTEXT2) {
128 key_len = ciphertext->len;
129 } else {
130 key_len = get_aead_key_len(suite->edhoc_aead);
131 }
132
133 BYTE_ARRAY_NEW(key, CIPHERTEXT2_SIZE, key_len);
134 BYTE_ARRAY_NEW(iv, AEAD_IV_SIZE, get_aead_iv_len(suite->edhoc_aead));
135
136 TRY(key_gen(ctxt, suite->edhoc_hash, prk, th, &key, &iv));
137
138 /*Associated data*/
139 BYTE_ARRAY_NEW(associated_data, AAD_SIZE, AAD_SIZE);
140 TRY(associated_data_encode(th, &associated_data));
141
142 PRINT_ARRAY("associated_data", associated_data.ptr,
143 associated_data.len);
144
145 uint32_t tag_len = get_aead_mac_len(suite->edhoc_aead);
146 if (ctxt != CIPHERTEXT2) {
147 if (plaintext->len < tag_len) {
148 return error_message_received;
149 }
150 plaintext->len -= tag_len;
151 }
152 struct byte_array tag = BYTE_ARRAY_INIT(ciphertext->ptr, tag_len);
153 TRY(ciphertext_encrypt_decrypt(ctxt, DECRYPT, ciphertext, &key, &iv,
154 &associated_data, plaintext, &tag));
155
156 PRINT_ARRAY("plaintext", plaintext->ptr, plaintext->len);
157
158 if (ctxt == CIPHERTEXT4 && plaintext->len != 0) {
159 TRY(decode_bstr(plaintext, ead));
160 PRINT_ARRAY("EAD_4", ead->ptr, ead->len);
161 } else if (ctxt == CIPHERTEXT4 && plaintext->len == 0) {
162 ead->ptr = NULL;
163 ead->len = 0;
164 PRINT_MSG("No EAD_4\n");
165 } else {
166 if (ctxt == CIPHERTEXT2) {
167 TRY(plaintext_split(plaintext, c_r, id_cred, sig_or_mac,
168 ead));
169 PRINT_ARRAY("C_R (raw)", c_r->ptr, c_r->len);
170 } else {
171 TRY(plaintext_split(plaintext, NULL, id_cred,
172 sig_or_mac, ead));
173 }
174 PRINT_ARRAY("ID_CRED", id_cred->ptr, id_cred->len);
175 PRINT_ARRAY("sign_or_mac", sig_or_mac->ptr, sig_or_mac->len);
176 if (ead->len) {
177 PRINT_ARRAY("ead", ead->ptr, ead->len);
178 }
179 }
180
181 return ok;
182 }
183
ciphertext_gen(enum ciphertext ctxt,struct suite * suite,const struct byte_array * c_r,const struct byte_array * id_cred,struct byte_array * signature_or_mac,const struct byte_array * ead,struct byte_array * prk,struct byte_array * th,struct byte_array * ciphertext,struct byte_array * plaintext)184 enum err ciphertext_gen(enum ciphertext ctxt, struct suite *suite,
185 const struct byte_array *c_r,
186 const struct byte_array *id_cred,
187 struct byte_array *signature_or_mac,
188 const struct byte_array *ead, struct byte_array *prk,
189 struct byte_array *th, struct byte_array *ciphertext,
190 struct byte_array *plaintext)
191 {
192 BYTE_ARRAY_NEW(signature_or_mac_enc, AS_BSTR_SIZE(SIG_OR_MAC_SIZE),
193 AS_BSTR_SIZE(signature_or_mac->len));
194
195 TRY(encode_bstr(signature_or_mac, &signature_or_mac_enc));
196
197 uint32_t ptxt_buf_capacity = plaintext->len;
198 plaintext->len = 0;
199 if (ctxt == CIPHERTEXT2) {
200 if (c_x_is_encoded_int(c_r)) {
201 TRY(byte_array_append(plaintext, c_r,
202 ptxt_buf_capacity));
203 } else {
204 BYTE_ARRAY_NEW(c_r_enc, AS_BSTR_SIZE(C_I_SIZE),
205 AS_BSTR_SIZE(c_r->len));
206 TRY(encode_bstr(c_r, &c_r_enc));
207 TRY(byte_array_append(plaintext, &c_r_enc,
208 ptxt_buf_capacity));
209 }
210 }
211
212 if (ctxt != CIPHERTEXT4) {
213 BYTE_ARRAY_NEW(kid, KID_SIZE, KID_SIZE);
214 TRY(id_cred2kid(id_cred, &kid));
215
216 PRINT_ARRAY("kid", kid.ptr, kid.len);
217
218 if (kid.len != 0) {
219 /*id_cred_x is a KID*/
220 TRY(byte_array_append(plaintext, &kid,
221 ptxt_buf_capacity));
222 } else {
223 /*id_cred_x is NOT a KID*/
224 TRY(byte_array_append(plaintext, id_cred,
225 ptxt_buf_capacity));
226 }
227 TRY(byte_array_append(plaintext, &signature_or_mac_enc,
228 ptxt_buf_capacity));
229 } else {
230 plaintext->len = 0;
231 }
232 if (ead->len > 0) {
233 TRY(byte_array_append(plaintext, ead, ptxt_buf_capacity));
234 }
235
236 PRINT_ARRAY("plaintext", plaintext->ptr, plaintext->len);
237
238 /*generate key and iv (no iv in for ciphertext 2)*/
239 uint32_t key_len;
240 if (ctxt == CIPHERTEXT2) {
241 key_len = plaintext->len;
242 } else {
243 key_len = get_aead_key_len(suite->edhoc_aead);
244 }
245
246 BYTE_ARRAY_NEW(key, CIPHERTEXT2_SIZE, key_len);
247 BYTE_ARRAY_NEW(iv, AEAD_IV_SIZE, get_aead_iv_len(suite->edhoc_aead));
248
249 TRY(key_gen(ctxt, suite->edhoc_hash, prk, th, &key, &iv));
250
251 /*encrypt*/
252 BYTE_ARRAY_NEW(aad, AAD_SIZE, AAD_SIZE);
253 BYTE_ARRAY_NEW(tag, MAC_SIZE, get_aead_mac_len(suite->edhoc_aead));
254
255 if (ctxt != CIPHERTEXT2) {
256 /*Associated data*/
257 TRY(associated_data_encode(th, &aad));
258 PRINT_ARRAY("aad_data", aad.ptr, aad.len);
259 } else {
260 tag.len = 0;
261 }
262
263 ciphertext->len = plaintext->len;
264
265 TRY(ciphertext_encrypt_decrypt(ctxt, ENCRYPT, plaintext, &key, &iv,
266 &aad, ciphertext, &tag));
267 ciphertext->len += tag.len;
268
269 PRINT_ARRAY("ciphertext_2/3/4", ciphertext->ptr, ciphertext->len);
270 return ok;
271 }
272