2
* lib/crypto/arcfour/arcfour_aead.c
4
* Copyright 2008 by the Massachusetts Institute of Technology.
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.
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.
30
#include "arcfour-int.h"
35
static krb5_error_code
36
krb5int_arcfour_crypto_length(const struct krb5_aead_provider *aead,
37
const struct krb5_enc_provider *enc,
38
const struct krb5_hash_provider *hash,
43
case KRB5_CRYPTO_TYPE_HEADER:
44
*length = hash->hashsize + CONFOUNDERLENGTH;
46
case KRB5_CRYPTO_TYPE_PADDING:
49
case KRB5_CRYPTO_TYPE_TRAILER:
52
case KRB5_CRYPTO_TYPE_CHECKSUM:
53
*length = hash->hashsize;
56
assert(0 && "invalid cryptotype passed to krb5int_arcfour_crypto_length");
63
static krb5_error_code
64
alloc_derived_key(const struct krb5_enc_provider *enc,
67
const krb5_keyblock *src)
69
data->length = enc->keybytes;
70
data->data = malloc(data->length);
71
if (data->data == NULL)
75
dst->length = data->length;
76
dst->contents = (void *)data->data;
81
static krb5_error_code
82
krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
83
const struct krb5_enc_provider *enc,
84
const struct krb5_hash_provider *hash,
85
const krb5_keyblock *key,
87
const krb5_data *ivec,
88
krb5_crypto_iov *data,
92
krb5_crypto_iov *header, *trailer;
93
krb5_keyblock k1, k2, k3;
95
krb5_data checksum, confounder, header_data;
96
krb5_keyusage ms_usage;
101
d1.length = d2.length = d3.length = 0;
102
d1.data = d2.data = d3.data = NULL;
105
* Caller must have provided space for the header, padding
106
* and trailer; per RFC 4757 we will arrange it as:
108
* Checksum | E(Confounder | Plaintext)
111
header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
112
if (header == NULL ||
113
header->data.length < hash->hashsize + CONFOUNDERLENGTH)
114
return KRB5_BAD_MSIZE;
116
header_data = header->data;
118
/* Trailer may be absent */
119
trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
121
trailer->data.length = 0;
123
/* Ensure that there is no padding */
124
for (i = 0; i < num_data; i++) {
125
if (data[i].flags == KRB5_CRYPTO_TYPE_PADDING)
126
data[i].data.length = 0;
129
ret = alloc_derived_key(enc, &k1, &d1, key);
133
ret = alloc_derived_key(enc, &k2, &d2, key);
137
ret = alloc_derived_key(enc, &k3, &d3, key);
141
/* Begin the encryption, compute K1 */
142
salt.data = salt_data;
143
salt.length = sizeof(salt_data);
145
ms_usage = krb5int_arcfour_translate_usage(usage);
147
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
148
strncpy(salt.data, krb5int_arcfour_l40, salt.length);
149
store_32_le(ms_usage, salt.data + 10);
152
store_32_le(ms_usage, salt.data);
154
ret = krb5_hmac(hash, key, 1, &salt, &d1);
158
memcpy(k2.contents, k1.contents, k2.length);
160
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
161
memset(k1.contents + 7, 0xAB, 9);
163
header->data.length = hash->hashsize + CONFOUNDERLENGTH;
165
confounder.data = header->data.data + hash->hashsize;
166
confounder.length = CONFOUNDERLENGTH;
168
ret = krb5_c_random_make_octets(0, &confounder);
172
checksum.data = header->data.data;
173
checksum.length = hash->hashsize;
175
/* Adjust pointers so confounder is at start of header */
176
header->data.length -= hash->hashsize;
177
header->data.data += hash->hashsize;
179
ret = krb5int_hmac_iov(hash, &k2, data, num_data, &checksum);
183
ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
187
ret = enc->encrypt_iov(&k3, ivec, data, num_data);
192
header->data = header_data; /* restore header pointers */
194
if (d1.data != NULL) {
195
memset(d1.data, 0, d1.length);
198
if (d2.data != NULL) {
199
memset(d2.data, 0, d2.length);
202
if (d3.data != NULL) {
203
memset(d3.data, 0, d3.length);
210
static krb5_error_code
211
krb5int_arcfour_decrypt_iov(const struct krb5_aead_provider *aead,
212
const struct krb5_enc_provider *enc,
213
const struct krb5_hash_provider *hash,
214
const krb5_keyblock *key,
216
const krb5_data *ivec,
217
krb5_crypto_iov *data,
221
krb5_crypto_iov *header, *trailer;
222
krb5_keyblock k1, k2, k3;
223
krb5_data d1, d2, d3;
224
krb5_data checksum, header_data;
225
krb5_keyusage ms_usage;
229
d1.length = d2.length = d3.length = 0;
230
d1.data = d2.data = d3.data = NULL;
232
header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
233
if (header == NULL ||
234
header->data.length != hash->hashsize + CONFOUNDERLENGTH)
235
return KRB5_BAD_MSIZE;
237
header_data = header->data;
239
trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
240
if (trailer != NULL && trailer->data.length != 0)
241
return KRB5_BAD_MSIZE;
243
ret = alloc_derived_key(enc, &k1, &d1, key);
247
ret = alloc_derived_key(enc, &k2, &d2, key);
251
ret = alloc_derived_key(enc, &k3, &d3, key);
255
/* Begin the decryption, compute K1 */
256
salt.data = salt_data;
257
salt.length = sizeof(salt_data);
259
ms_usage = krb5int_arcfour_translate_usage(usage);
261
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
262
strncpy(salt.data, krb5int_arcfour_l40, salt.length);
263
store_32_le(ms_usage, (unsigned char *)salt.data + 10);
266
store_32_le(ms_usage, (unsigned char *)salt.data);
268
ret = krb5_hmac(hash, key, 1, &salt, &d1);
272
memcpy(k2.contents, k1.contents, k2.length);
274
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
275
memset(k1.contents + 7, 0xAB, 9);
277
checksum.data = header->data.data;
278
checksum.length = hash->hashsize;
280
/* Adjust pointers so confounder is at start of header */
281
header->data.length -= hash->hashsize;
282
header->data.data += hash->hashsize;
284
ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
288
ret = enc->decrypt_iov(&k3, ivec, data, num_data);
292
ret = krb5int_hmac_iov(hash, &k2, data, num_data, &d1);
296
if (memcmp(checksum.data, d1.data, hash->hashsize) != 0) {
297
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
302
header->data = header_data; /* restore header pointers */
304
if (d1.data != NULL) {
305
memset(d1.data, 0, d1.length);
308
if (d2.data != NULL) {
309
memset(d2.data, 0, d2.length);
312
if (d3.data != NULL) {
313
memset(d3.data, 0, d3.length);
320
const struct krb5_aead_provider krb5int_aead_arcfour = {
321
krb5int_arcfour_crypto_length,
322
krb5int_arcfour_encrypt_iov,
323
krb5int_arcfour_decrypt_iov