1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/crypto_tests/t_encrypt.c */
3 /*
4 * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 *
29 * <<< Description >>>
30 */
31 /*
32 * Some black-box tests of crypto systems. Make sure that we can decrypt things we encrypt, etc.
33 */
34
35 #include "crypto_int.h"
36 #include <stdio.h>
37
38 /* What enctypes should we test?*/
39 krb5_enctype interesting_enctypes[] = {
40 ENCTYPE_DES3_CBC_SHA1,
41 ENCTYPE_ARCFOUR_HMAC,
42 ENCTYPE_ARCFOUR_HMAC_EXP,
43 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
44 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
45 ENCTYPE_CAMELLIA128_CTS_CMAC,
46 ENCTYPE_CAMELLIA256_CTS_CMAC,
47 ENCTYPE_AES128_CTS_HMAC_SHA256_128,
48 ENCTYPE_AES256_CTS_HMAC_SHA384_192,
49 0
50 };
51
52 static void
test(const char * msg,krb5_error_code retval)53 test(const char *msg, krb5_error_code retval)
54 {
55 printf("%s: . . . ", msg);
56 if (retval) {
57 printf("Failed: %s\n", error_message(retval));
58 abort();
59 } else
60 printf("OK\n");
61 }
62
compare_results(krb5_data * d1,krb5_data * d2)63 static int compare_results(krb5_data *d1, krb5_data *d2)
64 {
65 if (d1->length != d2->length) {
66 /* Decryption can leave a little trailing cruft.
67 For the current cryptosystems, this can be up to 7 bytes. */
68 if (d1->length + 8 <= d2->length)
69 return EINVAL;
70 if (d1->length > d2->length)
71 return EINVAL;
72 }
73 if (memcmp(d1->data, d2->data, d1->length)) {
74 return EINVAL;
75 }
76 return 0;
77 }
78
79 static void
display(const char * msg,const krb5_data * d)80 display(const char *msg, const krb5_data *d)
81 {
82 unsigned int i;
83
84 printf("%s:", msg);
85 for (i = 0; i < d->length; i++)
86 printf(" %02X", (unsigned char) d->data[i]);
87 printf("\n");
88 }
89
90 int
main(void)91 main(void)
92 {
93 krb5_context context = 0;
94 krb5_data in, in2, out, out2, check, check2, state, signdata;
95 krb5_crypto_iov iov[5];
96 int i, j, pos;
97 unsigned int dummy;
98 size_t len;
99 krb5_enc_data enc_out, enc_out2;
100 krb5_keyblock *keyblock;
101 krb5_key key;
102
103 memset(iov, 0, sizeof(iov));
104
105 in.data = "This is a test.\n";
106 in.length = strlen (in.data);
107 in2.data = "This is another test.\n";
108 in2.length = strlen (in2.data);
109
110 test ("Seeding random number generator",
111 krb5_c_random_seed (context, &in));
112
113 /* Set up output buffers. */
114 out.data = malloc(2048);
115 out2.data = malloc(2048);
116 check.data = malloc(2048);
117 check2.data = malloc(2048);
118 if (out.data == NULL || out2.data == NULL
119 || check.data == NULL || check2.data == NULL)
120 abort();
121 out.magic = KV5M_DATA;
122 out.length = 2048;
123 out2.magic = KV5M_DATA;
124 out2.length = 2048;
125 check.length = 2048;
126 check2.length = 2048;
127
128 for (i = 0; interesting_enctypes[i]; i++) {
129 krb5_enctype enctype = interesting_enctypes [i];
130
131 printf ("Testing enctype %d\n", enctype);
132 test ("Initializing a keyblock",
133 krb5_init_keyblock (context, enctype, 0, &keyblock));
134 test ("Generating random keyblock",
135 krb5_c_make_random_key (context, enctype, keyblock));
136 test ("Creating opaque key from keyblock",
137 krb5_k_create_key (context, keyblock, &key));
138
139 enc_out.ciphertext = out;
140 enc_out2.ciphertext = out2;
141 /* We use an intermediate `len' because size_t may be different size
142 than `int' */
143 krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
144 enc_out.ciphertext.length = len;
145
146 /* Encrypt, decrypt, and see if we got the plaintext back again. */
147 test ("Encrypting (c)",
148 krb5_c_encrypt (context, keyblock, 7, 0, &in, &enc_out));
149 display ("Enc output", &enc_out.ciphertext);
150 test ("Decrypting",
151 krb5_c_decrypt (context, keyblock, 7, 0, &enc_out, &check));
152 test ("Comparing", compare_results (&in, &check));
153
154 /* Try again with the opaque-key-using variants. */
155 memset(out.data, 0, out.length);
156 test ("Encrypting (k)",
157 krb5_k_encrypt (context, key, 7, 0, &in, &enc_out));
158 display ("Enc output", &enc_out.ciphertext);
159 test ("Decrypting",
160 krb5_k_decrypt (context, key, 7, 0, &enc_out, &check));
161 test ("Comparing", compare_results (&in, &check));
162
163 /* Check if this enctype supports IOV encryption. */
164 if ( krb5_c_crypto_length(context, keyblock->enctype,
165 KRB5_CRYPTO_TYPE_HEADER, &dummy) == 0 ){
166 /* Set up iovecs for stream decryption. */
167 memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
168 iov[0].flags= KRB5_CRYPTO_TYPE_STREAM;
169 iov[0].data.data = out2.data;
170 iov[0].data.length = enc_out.ciphertext.length;
171 iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
172
173 /* Decrypt the encrypted data from above and check it. */
174 test("IOV stream decrypting (c)",
175 krb5_c_decrypt_iov( context, keyblock, 7, 0, iov, 2));
176 test("Comparing results",
177 compare_results(&in, &iov[1].data));
178
179 /* Try again with the opaque-key-using variant. */
180 memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
181 test("IOV stream decrypting (k)",
182 krb5_k_decrypt_iov( context, key, 7, 0, iov, 2));
183 test("Comparing results",
184 compare_results(&in, &iov[1].data));
185
186 /* Set up iovecs for AEAD encryption. */
187 signdata.magic = KV5M_DATA;
188 signdata.data = (char *) "This should be signed";
189 signdata.length = strlen(signdata.data);
190 iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
191 iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
192 iov[1].data = in; /*We'll need to copy memory before encrypt*/
193 iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
194 iov[2].data = signdata;
195 iov[3].flags = KRB5_CRYPTO_TYPE_PADDING;
196 iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER;
197
198 /* "Allocate" data for the iovec buffers from the "out" buffer. */
199 test("Setting up iov lengths",
200 krb5_c_crypto_length_iov(context, keyblock->enctype, iov, 5));
201 for (j=0,pos=0; j <= 4; j++ ){
202 if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
203 continue;
204 iov[j].data.data = &out.data[pos];
205 pos += iov[j].data.length;
206 }
207 assert (iov[1].data.length == in.length);
208 memcpy(iov[1].data.data, in.data, in.length);
209
210 /* Encrypt and decrypt in place, and check the result. */
211 test("iov encrypting (c)",
212 krb5_c_encrypt_iov(context, keyblock, 7, 0, iov, 5));
213 assert(iov[1].data.length == in.length);
214 display("Header", &iov[0].data);
215 display("Data", &iov[1].data);
216 display("Padding", &iov[3].data);
217 display("Trailer", &iov[4].data);
218 test("iov decrypting",
219 krb5_c_decrypt_iov(context, keyblock, 7, 0, iov, 5));
220 test("Comparing results",
221 compare_results(&in, &iov[1].data));
222
223 /* Try again with opaque-key-using variants. */
224 test("iov encrypting (k)",
225 krb5_k_encrypt_iov(context, key, 7, 0, iov, 5));
226 assert(iov[1].data.length == in.length);
227 display("Header", &iov[0].data);
228 display("Data", &iov[1].data);
229 display("Padding", &iov[3].data);
230 display("Trailer", &iov[4].data);
231 test("iov decrypting",
232 krb5_k_decrypt_iov(context, key, 7, 0, iov, 5));
233 test("Comparing results",
234 compare_results(&in, &iov[1].data));
235 }
236
237 enc_out.ciphertext.length = out.length;
238 check.length = 2048;
239
240 test ("init_state",
241 krb5_c_init_state (context, keyblock, 7, &state));
242 test ("Encrypting with state",
243 krb5_c_encrypt (context, keyblock, 7, &state, &in, &enc_out));
244 display ("Enc output", &enc_out.ciphertext);
245 test ("Encrypting again with state",
246 krb5_c_encrypt (context, keyblock, 7, &state, &in2, &enc_out2));
247 display ("Enc output", &enc_out2.ciphertext);
248 test ("free_state",
249 krb5_c_free_state (context, keyblock, &state));
250 test ("init_state",
251 krb5_c_init_state (context, keyblock, 7, &state));
252 test ("Decrypting with state",
253 krb5_c_decrypt (context, keyblock, 7, &state, &enc_out, &check));
254 test ("Decrypting again with state",
255 krb5_c_decrypt (context, keyblock, 7, &state, &enc_out2, &check2));
256 test ("free_state",
257 krb5_c_free_state (context, keyblock, &state));
258 test ("Comparing",
259 compare_results (&in, &check));
260 test ("Comparing",
261 compare_results (&in2, &check2));
262
263 krb5_free_keyblock (context, keyblock);
264 krb5_k_free_key (context, key);
265 }
266
267 /* Test the RC4 decrypt fallback from key usage 9 to 8. */
268 test ("Initializing an RC4 keyblock",
269 krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &keyblock));
270 test ("Generating random RC4 key",
271 krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, keyblock));
272 enc_out.ciphertext = out;
273 krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
274 enc_out.ciphertext.length = len;
275 check.length = 2048;
276 test ("Encrypting with RC4 key usage 8",
277 krb5_c_encrypt (context, keyblock, 8, 0, &in, &enc_out));
278 display ("Enc output", &enc_out.ciphertext);
279 test ("Decrypting with RC4 key usage 9",
280 krb5_c_decrypt (context, keyblock, 9, 0, &enc_out, &check));
281 test ("Comparing", compare_results (&in, &check));
282
283 krb5_free_keyblock (context, keyblock);
284 free(out.data);
285 free(out2.data);
286 free(check.data);
287 free(check2.data);
288 return 0;
289 }
290