1/*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "krb5_locl.h"
35
36/*
37 * AES
38 */
39
40#ifdef __APPLE_TARGET_EMBEDDED__
41
42#include <CommonCrypto/CommonCryptor.h>
43#include <CommonCrypto/CommonCryptorSPI.h>
44
45/*
46 * CommonCrypto based
47 */
48
49struct cc_schedule {
50    CCCryptorRef enc;
51    CCCryptorRef dec;
52    struct _krb5_key_type *kt;
53};
54
55static void
56_krb5_cc_schedule(krb5_context context,
57		  struct _krb5_key_type *kt,
58		  struct _krb5_key_data *kd)
59{
60    struct cc_schedule *key = kd->schedule->data;
61    CCAlgorithm alg = (CCAlgorithm)kt->evp;
62
63    key->kt = kt;
64
65    if (CCCryptorCreateWithMode(kCCEncrypt,
66				kCCModeCBC,
67				alg,
68				ccCBCCTS3,
69				NULL,
70				kd->key->keyvalue.data,
71				kd->key->keyvalue.length,
72				NULL,
73				0,
74				0,
75				0,
76				&key->enc) != 0)
77	abort();
78
79    if (CCCryptorCreateWithMode(kCCDecrypt,
80				kCCModeCBC,
81				alg,
82				ccCBCCTS3,
83				NULL,
84				kd->key->keyvalue.data,
85				kd->key->keyvalue.length,
86				NULL,
87				0,
88				0,
89				0,
90				&key->dec) != 0)
91	abort();
92}
93
94static void
95_krb5_cc_cleanup(krb5_context context, struct _krb5_key_data *kd)
96{
97    struct cc_schedule *key = kd->schedule->data;
98    CCCryptorRelease(key->enc);
99    CCCryptorRelease(key->dec);
100}
101
102static struct _krb5_key_type keytype_aes128 = {
103    ENCTYPE_AES128_CTS_HMAC_SHA1_96,
104    "aes-128",
105    128,
106    16,
107    sizeof(struct cc_schedule),
108    NULL,
109    _krb5_cc_schedule,
110    _krb5_AES_salt,
111    NULL,
112    _krb5_cc_cleanup,
113    (void *)kCCAlgorithmAES128
114};
115
116static struct _krb5_key_type keytype_aes256 = {
117    ENCTYPE_AES256_CTS_HMAC_SHA1_96,
118    "aes-256",
119    256,
120    32,
121    sizeof(struct cc_schedule),
122    NULL,
123    _krb5_cc_schedule,
124    _krb5_AES_salt,
125    NULL,
126    _krb5_cc_cleanup,
127    (void *)kCCAlgorithmAES128
128};
129
130struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = {
131    CKSUMTYPE_HMAC_SHA1_96_AES_128,
132    "hmac-sha1-96-aes128",
133    64,
134    12,
135    F_KEYED | F_CPROOF | F_DERIVED,
136    _krb5_SP_HMAC_SHA1_checksum,
137    NULL
138};
139
140struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = {
141    CKSUMTYPE_HMAC_SHA1_96_AES_256,
142    "hmac-sha1-96-aes256",
143    64,
144    12,
145    F_KEYED | F_CPROOF | F_DERIVED,
146    _krb5_SP_HMAC_SHA1_checksum,
147    NULL
148};
149
150static krb5_error_code
151cc_AES_PRF(krb5_context context,
152	   krb5_crypto crypto,
153	   const krb5_data *in,
154	   krb5_data *out)
155{
156    struct _krb5_checksum_type *ct = crypto->et->checksum;
157    krb5_error_code ret;
158    Checksum result;
159    krb5_keyblock *derived;
160
161    result.cksumtype = ct->type;
162    ret = krb5_data_alloc(&result.checksum, ct->checksumsize);
163    if (ret) {
164	krb5_set_error_message(context, ret, N_("malloc: out memory", ""));
165	return ret;
166    }
167
168    ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result);
169    if (ret) {
170	krb5_data_free(&result.checksum);
171	return ret;
172    }
173
174    if (result.checksum.length < crypto->et->blocksize)
175	krb5_abortx(context, "internal prf error");
176
177    derived = NULL;
178    ret = krb5_derive_key(context, crypto->key.key,
179			  crypto->et->type, "prf", 3, &derived);
180    if (ret)
181	krb5_abortx(context, "krb5_derive_key");
182
183    ret = krb5_data_alloc(out, crypto->et->blocksize);
184    if (ret)
185	krb5_abortx(context, "malloc failed");
186
187    {
188	CCAlgorithm alg = (CCAlgorithm)crypto->et->keytype->evp;
189	CCCryptorStatus s;
190	size_t moved;
191
192	s = CCCrypt(kCCEncrypt,
193		    alg,
194		    0,
195		    derived->keyvalue.data,
196		    crypto->et->keytype->size,
197		    NULL,
198		    result.checksum.data,
199		    crypto->et->blocksize,
200		    out->data,
201		    crypto->et->blocksize,
202		    &moved);
203	if (s)
204	    krb5_abortx(context, "encrypt failed");
205	if (moved != crypto->et->blocksize)
206	    krb5_abortx(context, "encrypt failed");
207
208    }
209
210    krb5_data_free(&result.checksum);
211    krb5_free_keyblock(context, derived);
212
213    return ret;
214}
215
216static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };
217
218static krb5_error_code
219_krb5_cc_encrypt_cts(krb5_context context,
220		     struct _krb5_key_data *key,
221		     void *data,
222		     size_t len,
223		     krb5_boolean encryptp,
224		     int usage,
225		     void *ivec)
226{
227    struct cc_schedule *ctx = key->schedule->data;
228    size_t blocksize;
229    unsigned char *p, *p0;
230    size_t moved, plen = len;
231    CCCryptorStatus s;
232    CCCryptorRef c;
233
234    c = encryptp ? ctx->enc : ctx->dec;
235
236    p0 = p = malloc(len);
237    if (p0 == NULL)
238	return ENOMEM;
239
240    blocksize = 16; /* XXX only for aes now */
241
242    if (len < blocksize) {
243	krb5_set_error_message(context, EINVAL,
244			       "message block too short");
245	return EINVAL;
246    } else if (len == blocksize) {
247	struct _krb5_key_type *kt = ctx->kt;
248	CCAlgorithm alg = (CCAlgorithm)kt->evp;
249
250	s = CCCrypt(encryptp ? kCCEncrypt : kCCDecrypt,
251		    alg,
252		    0,
253		    key->key->keyvalue.data,
254		    key->key->keyvalue.length,
255		    NULL,
256		    data,
257		    len,
258		    data,
259		    len,
260		    &moved);
261	heim_assert(s == 0, "CCCrypt failed");
262	heim_assert(moved == len, "moved == len");
263
264	return 0;
265    }
266
267    if (ivec)
268	CCCryptorReset(c, ivec);
269    else
270	CCCryptorReset(c, zero_ivec);
271
272    s = CCCryptorUpdate(c, data, len, p, plen, &moved);
273    heim_assert(s == 0, "CCCryptorUpdate failed");
274    plen -= moved;
275    p += moved;
276    s = CCCryptorFinal(c, p, plen, &moved);
277    heim_assert(s == 0, "CCCryptorFinal failed");
278    plen -= moved;
279    heim_assert(plen == 0, "plen == 0");
280
281    memcpy(data, p0, len);
282    free(p0);
283
284    return 0;
285}
286
287
288struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = {
289    ETYPE_AES128_CTS_HMAC_SHA1_96,
290    "aes128-cts-hmac-sha1-96",
291    16,
292    1,
293    16,
294    &keytype_aes128,
295    &_krb5_checksum_sha1,
296    &_krb5_checksum_hmac_sha1_aes128,
297    F_DERIVED,
298    _krb5_cc_encrypt_cts,
299    16,
300    cc_AES_PRF
301};
302
303struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = {
304    ETYPE_AES256_CTS_HMAC_SHA1_96,
305    "aes256-cts-hmac-sha1-96",
306    16,
307    1,
308    16,
309    &keytype_aes256,
310    &_krb5_checksum_sha1,
311    &_krb5_checksum_hmac_sha1_aes256,
312    F_DERIVED,
313    _krb5_cc_encrypt_cts,
314    16,
315    cc_AES_PRF
316};
317
318#else
319
320/*
321 * EVP based
322 */
323
324static struct _krb5_key_type keytype_aes128 = {
325    KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96,
326    "aes-128",
327    128,
328    16,
329    sizeof(struct _krb5_evp_schedule),
330    NULL,
331    _krb5_evp_schedule,
332    _krb5_AES_salt,
333    NULL,
334    _krb5_evp_cleanup,
335    EVP_aes_128_cbc
336};
337
338static struct _krb5_key_type keytype_aes256 = {
339    KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
340    "aes-256",
341    256,
342    32,
343    sizeof(struct _krb5_evp_schedule),
344    NULL,
345    _krb5_evp_schedule,
346    _krb5_AES_salt,
347    NULL,
348    _krb5_evp_cleanup,
349    EVP_aes_256_cbc
350};
351
352struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128 = {
353    CKSUMTYPE_HMAC_SHA1_96_AES_128,
354    "hmac-sha1-96-aes128",
355    64,
356    12,
357    F_KEYED | F_CPROOF | F_DERIVED,
358    _krb5_SP_HMAC_SHA1_checksum,
359    NULL
360};
361
362struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = {
363    CKSUMTYPE_HMAC_SHA1_96_AES_256,
364    "hmac-sha1-96-aes256",
365    64,
366    12,
367    F_KEYED | F_CPROOF | F_DERIVED,
368    _krb5_SP_HMAC_SHA1_checksum,
369    NULL
370};
371
372static krb5_error_code
373AES_PRF(krb5_context context,
374	krb5_crypto crypto,
375	const krb5_data *in,
376	krb5_data *out)
377{
378    struct _krb5_checksum_type *ct = crypto->et->checksum;
379    krb5_error_code ret;
380    Checksum result;
381    krb5_keyblock *derived;
382
383    result.cksumtype = ct->type;
384    ret = krb5_data_alloc(&result.checksum, ct->checksumsize);
385    if (ret) {
386	krb5_set_error_message(context, ret, N_("malloc: out memory", ""));
387	return ret;
388    }
389
390    ret = (*ct->checksum)(context, NULL, in->data, in->length, 0, &result);
391    if (ret) {
392	krb5_data_free(&result.checksum);
393	return ret;
394    }
395
396    if (result.checksum.length < crypto->et->blocksize)
397	krb5_abortx(context, "internal prf error");
398
399    derived = NULL;
400    ret = krb5_derive_key(context, crypto->key.key,
401			  crypto->et->type, "prf", 3, &derived);
402    if (ret)
403	krb5_abortx(context, "krb5_derive_key");
404
405    ret = krb5_data_alloc(out, crypto->et->blocksize);
406    if (ret)
407	krb5_abortx(context, "malloc failed");
408
409    {
410	const EVP_CIPHER *c = (*crypto->et->keytype->evp)();
411	EVP_CIPHER_CTX ctx;
412
413	EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */
414	EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1);
415	EVP_Cipher(&ctx, out->data, result.checksum.data,
416		   crypto->et->blocksize);
417	EVP_CIPHER_CTX_cleanup(&ctx);
418    }
419
420    krb5_data_free(&result.checksum);
421    krb5_free_keyblock(context, derived);
422
423    return ret;
424}
425
426struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = {
427    ETYPE_AES128_CTS_HMAC_SHA1_96,
428    "aes128-cts-hmac-sha1-96",
429    16,
430    1,
431    16,
432    &keytype_aes128,
433    &_krb5_checksum_sha1,
434    &_krb5_checksum_hmac_sha1_aes128,
435    F_DERIVED,
436    _krb5_evp_encrypt_cts,
437    16,
438    AES_PRF
439};
440
441struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = {
442    ETYPE_AES256_CTS_HMAC_SHA1_96,
443    "aes256-cts-hmac-sha1-96",
444    16,
445    1,
446    16,
447    &keytype_aes256,
448    &_krb5_checksum_sha1,
449    &_krb5_checksum_hmac_sha1_aes256,
450    F_DERIVED,
451    _krb5_evp_encrypt_cts,
452    16,
453    AES_PRF
454};
455
456#endif
457