Branch data Line data Source code
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 : : */
35 : 6 : static inline enum err xor_arrays(const struct byte_array *in1,
36 : : const struct byte_array *in2,
37 : : struct byte_array *out)
38 : : {
39 [ - + ]: 6 : if (in1->len != in2->len) {
40 : 0 : return xor_error;
41 : : }
42 [ + + ]: 1058 : for (uint32_t i = 0; i < in1->len; i++) {
43 : 1052 : out->ptr[i] = in1->ptr[i] ^ in2->ptr[i];
44 : : }
45 : 6 : 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 : : */
61 : 12 : 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 [ + + ]: 12 : if (ctxt == CIPHERTEXT2) {
68 : 6 : xor_arrays(in, key, out);
69 : : } else {
70 : 6 : PRINT_ARRAY("in", in->ptr, in->len);
71 [ - + ]: 6 : TRY(aead(op, in, key, nonce, aad, out, tag));
72 : : }
73 : 12 : 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 : : */
88 : 12 : 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 [ + + - - ]: 12 : switch (ctxt) {
93 : 6 : case CIPHERTEXT2:
94 [ - + ]: 6 : TRY(edhoc_kdf(edhoc_hash, prk, KEYSTREAM_2, th, key));
95 : 6 : PRINT_ARRAY("KEYSTREAM_2", key->ptr, key->len);
96 : 6 : break;
97 : :
98 : 6 : case CIPHERTEXT3:
99 [ - + ]: 6 : TRY(edhoc_kdf(edhoc_hash, prk, K_3, th, key));
100 : :
101 : 6 : PRINT_ARRAY("K_3", key->ptr, key->len);
102 : :
103 [ - + ]: 6 : TRY(edhoc_kdf(edhoc_hash, prk, IV_3, th, iv));
104 : 6 : PRINT_ARRAY("IV_3", iv->ptr, iv->len);
105 : 6 : break;
106 : :
107 : 0 : case CIPHERTEXT4:
108 : 0 : PRINT_ARRAY("PRK_4e3m", prk->ptr, prk->len);
109 : 0 : PRINT_ARRAY("TH_4", th->ptr, th->len);
110 [ # # ]: 0 : TRY(edhoc_kdf(edhoc_hash, prk, K_4, th, key));
111 : 0 : PRINT_ARRAY("K_4", key->ptr, key->len);
112 [ # # ]: 0 : TRY(edhoc_kdf(edhoc_hash, prk, IV_4, th, iv));
113 : 0 : PRINT_ARRAY("IV_4", iv->ptr, iv->len);
114 : 0 : break;
115 : : }
116 : 12 : return ok;
117 : : }
118 : :
119 : 6 : 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 [ + + ]: 6 : if (ctxt == CIPHERTEXT2) {
128 : 3 : key_len = ciphertext->len;
129 : : } else {
130 : 3 : key_len = get_aead_key_len(suite->edhoc_aead);
131 : : }
132 : :
133 [ - + - + ]: 6 : BYTE_ARRAY_NEW(key, CIPHERTEXT2_SIZE, key_len);
134 [ - + - + ]: 6 : BYTE_ARRAY_NEW(iv, AEAD_IV_SIZE, get_aead_iv_len(suite->edhoc_aead));
135 : :
136 [ - + ]: 6 : TRY(key_gen(ctxt, suite->edhoc_hash, prk, th, &key, &iv));
137 : :
138 : : /*Associated data*/
139 [ - + ]: 6 : BYTE_ARRAY_NEW(associated_data, AAD_SIZE, AAD_SIZE);
140 [ - + ]: 6 : TRY(associated_data_encode(th, &associated_data));
141 : :
142 : 6 : PRINT_ARRAY("associated_data", associated_data.ptr,
143 : : associated_data.len);
144 : :
145 : 6 : uint32_t tag_len = get_aead_mac_len(suite->edhoc_aead);
146 [ + + ]: 6 : if (ctxt != CIPHERTEXT2) {
147 [ - + ]: 3 : if (plaintext->len < tag_len) {
148 : 0 : return error_message_received;
149 : : }
150 : 3 : plaintext->len -= tag_len;
151 : : }
152 : 6 : struct byte_array tag = BYTE_ARRAY_INIT(ciphertext->ptr, tag_len);
153 [ - + ]: 6 : TRY(ciphertext_encrypt_decrypt(ctxt, DECRYPT, ciphertext, &key, &iv,
154 : : &associated_data, plaintext, &tag));
155 : :
156 : 6 : PRINT_ARRAY("plaintext", plaintext->ptr, plaintext->len);
157 : :
158 [ - + - - ]: 6 : if (ctxt == CIPHERTEXT4 && plaintext->len != 0) {
159 [ # # ]: 0 : TRY(decode_bstr(plaintext, ead));
160 : 0 : PRINT_ARRAY("EAD_4", ead->ptr, ead->len);
161 [ - + - - ]: 6 : } else if (ctxt == CIPHERTEXT4 && plaintext->len == 0) {
162 : 0 : ead->ptr = NULL;
163 : 0 : ead->len = 0;
164 : 0 : PRINT_MSG("No EAD_4\n");
165 : : } else {
166 [ + + ]: 6 : if (ctxt == CIPHERTEXT2) {
167 [ - + ]: 3 : TRY(plaintext_split(plaintext, c_r, id_cred, sig_or_mac,
168 : : ead));
169 : 3 : PRINT_ARRAY("C_R (raw)", c_r->ptr, c_r->len);
170 : : } else {
171 [ - + ]: 3 : TRY(plaintext_split(plaintext, NULL, id_cred,
172 : : sig_or_mac, ead));
173 : : }
174 : 6 : PRINT_ARRAY("ID_CRED", id_cred->ptr, id_cred->len);
175 : 6 : PRINT_ARRAY("sign_or_mac", sig_or_mac->ptr, sig_or_mac->len);
176 [ - + ]: 6 : if (ead->len) {
177 : 0 : PRINT_ARRAY("ead", ead->ptr, ead->len);
178 : : }
179 : : }
180 : :
181 : 6 : return ok;
182 : : }
183 : :
184 : 6 : 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 [ + - - + : 6 : BYTE_ARRAY_NEW(signature_or_mac_enc, AS_BSTR_SIZE(SIG_OR_MAC_SIZE),
- - - + +
- - + - -
- + + - -
+ - - ]
193 : : AS_BSTR_SIZE(signature_or_mac->len));
194 : :
195 [ - + ]: 6 : TRY(encode_bstr(signature_or_mac, &signature_or_mac_enc));
196 : :
197 : 6 : uint32_t ptxt_buf_capacity = plaintext->len;
198 : 6 : plaintext->len = 0;
199 [ + + ]: 6 : if (ctxt == CIPHERTEXT2) {
200 [ + + ]: 3 : if (c_x_is_encoded_int(c_r)) {
201 [ - + ]: 2 : TRY(byte_array_append(plaintext, c_r,
202 : : ptxt_buf_capacity));
203 : : } else {
204 [ - + - - : 1 : BYTE_ARRAY_NEW(c_r_enc, AS_BSTR_SIZE(C_I_SIZE),
- - - + -
+ - - - -
- + - + -
- - - ]
205 : : AS_BSTR_SIZE(c_r->len));
206 [ - + ]: 1 : TRY(encode_bstr(c_r, &c_r_enc));
207 [ - + ]: 1 : TRY(byte_array_append(plaintext, &c_r_enc,
208 : : ptxt_buf_capacity));
209 : : }
210 : : }
211 : :
212 [ + - ]: 6 : if (ctxt != CIPHERTEXT4) {
213 [ - + ]: 6 : BYTE_ARRAY_NEW(kid, KID_SIZE, KID_SIZE);
214 [ - + ]: 6 : TRY(id_cred2kid(id_cred, &kid));
215 : :
216 : 6 : PRINT_ARRAY("kid", kid.ptr, kid.len);
217 : :
218 [ - + ]: 6 : if (kid.len != 0) {
219 : : /*id_cred_x is a KID*/
220 [ # # ]: 0 : TRY(byte_array_append(plaintext, &kid,
221 : : ptxt_buf_capacity));
222 : : } else {
223 : : /*id_cred_x is NOT a KID*/
224 [ - + ]: 6 : TRY(byte_array_append(plaintext, id_cred,
225 : : ptxt_buf_capacity));
226 : : }
227 [ - + ]: 6 : TRY(byte_array_append(plaintext, &signature_or_mac_enc,
228 : : ptxt_buf_capacity));
229 : : } else {
230 : 0 : plaintext->len = 0;
231 : : }
232 [ - + ]: 6 : if (ead->len > 0) {
233 [ # # ]: 0 : TRY(byte_array_append(plaintext, ead, ptxt_buf_capacity));
234 : : }
235 : :
236 : 6 : 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 [ + + ]: 6 : if (ctxt == CIPHERTEXT2) {
241 : 3 : key_len = plaintext->len;
242 : : } else {
243 : 3 : key_len = get_aead_key_len(suite->edhoc_aead);
244 : : }
245 : :
246 [ - + - + ]: 6 : BYTE_ARRAY_NEW(key, CIPHERTEXT2_SIZE, key_len);
247 [ - + - + ]: 6 : BYTE_ARRAY_NEW(iv, AEAD_IV_SIZE, get_aead_iv_len(suite->edhoc_aead));
248 : :
249 [ - + ]: 6 : TRY(key_gen(ctxt, suite->edhoc_hash, prk, th, &key, &iv));
250 : :
251 : : /*encrypt*/
252 [ - + ]: 6 : BYTE_ARRAY_NEW(aad, AAD_SIZE, AAD_SIZE);
253 [ - + - + ]: 6 : BYTE_ARRAY_NEW(tag, MAC_SIZE, get_aead_mac_len(suite->edhoc_aead));
254 : :
255 [ + + ]: 6 : if (ctxt != CIPHERTEXT2) {
256 : : /*Associated data*/
257 [ - + ]: 3 : TRY(associated_data_encode(th, &aad));
258 : 3 : PRINT_ARRAY("aad_data", aad.ptr, aad.len);
259 : : } else {
260 : 3 : tag.len = 0;
261 : : }
262 : :
263 : 6 : ciphertext->len = plaintext->len;
264 : :
265 [ - + ]: 6 : TRY(ciphertext_encrypt_decrypt(ctxt, ENCRYPT, plaintext, &key, &iv,
266 : : &aad, ciphertext, &tag));
267 : 6 : ciphertext->len += tag.len;
268 : :
269 : 6 : PRINT_ARRAY("ciphertext_2/3/4", ciphertext->ptr, ciphertext->len);
270 : 6 : return ok;
271 : : }
|