1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/krb/enc_dk_cmac.c - Derived-key enctype functions using CMAC */
3 /*
4 * Copyright 2008, 2009, 2010 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 #include "crypto_int.h"
29
30 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
31
32 /* AEAD */
33
34 unsigned int
krb5int_camellia_crypto_length(const struct krb5_keytypes * ktp,krb5_cryptotype type)35 krb5int_camellia_crypto_length(const struct krb5_keytypes *ktp,
36 krb5_cryptotype type)
37 {
38 switch (type) {
39 case KRB5_CRYPTO_TYPE_HEADER:
40 return ktp->enc->block_size;
41 case KRB5_CRYPTO_TYPE_PADDING:
42 return 0;
43 case KRB5_CRYPTO_TYPE_TRAILER:
44 case KRB5_CRYPTO_TYPE_CHECKSUM:
45 return ktp->enc->block_size;
46 default:
47 assert(0 && "bad type passed to krb5int_camellia_crypto_length");
48 return 0;
49 }
50 }
51
52 /* Derive encryption and integrity keys for CMAC-using enctypes. */
53 static krb5_error_code
derive_keys(const struct krb5_enc_provider * enc,krb5_key key,krb5_keyusage usage,krb5_key * ke_out,krb5_key * ki_out)54 derive_keys(const struct krb5_enc_provider *enc, krb5_key key,
55 krb5_keyusage usage, krb5_key *ke_out, krb5_key *ki_out)
56 {
57 krb5_error_code ret;
58 unsigned char buf[K5CLENGTH];
59 krb5_data constant = make_data(buf, K5CLENGTH);
60 krb5_key ke, ki;
61
62 *ke_out = *ki_out = NULL;
63
64 /* Derive the encryption key. */
65 store_32_be(usage, buf);
66 buf[4] = 0xAA;
67 ret = krb5int_derive_key(enc, NULL, key, &ke, &constant,
68 DERIVE_SP800_108_CMAC);
69 if (ret != 0)
70 return ret;
71
72 /* Derive the integrity key. */
73 buf[4] = 0x55;
74 ret = krb5int_derive_key(enc, NULL, key, &ki, &constant,
75 DERIVE_SP800_108_CMAC);
76 if (ret != 0) {
77 krb5_k_free_key(NULL, ke);
78 return ret;
79 }
80
81 *ke_out = ke;
82 *ki_out = ki;
83 return 0;
84 }
85
86 krb5_error_code
krb5int_dk_cmac_encrypt(const struct krb5_keytypes * ktp,krb5_key key,krb5_keyusage usage,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)87 krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key,
88 krb5_keyusage usage, const krb5_data *ivec,
89 krb5_crypto_iov *data, size_t num_data)
90 {
91 const struct krb5_enc_provider *enc = ktp->enc;
92 krb5_error_code ret;
93 krb5_crypto_iov *header, *trailer, *padding;
94 krb5_key ke = NULL, ki = NULL;
95
96 /* E(Confounder | Plaintext | Pad) | Checksum */
97
98 /* Validate header and trailer lengths, and zero out padding length. */
99 header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
100 if (header == NULL || header->data.length < enc->block_size)
101 return KRB5_BAD_MSIZE;
102 trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
103 if (trailer == NULL || trailer->data.length < enc->block_size)
104 return KRB5_BAD_MSIZE;
105 padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
106 if (padding != NULL)
107 padding->data.length = 0;
108
109 /* Derive the encryption and integrity keys. */
110 ret = derive_keys(enc, key, usage, &ke, &ki);
111 if (ret != 0)
112 goto cleanup;
113
114 /* Generate confounder. */
115 header->data.length = enc->block_size;
116 ret = krb5_c_random_make_octets(NULL, &header->data);
117 if (ret != 0)
118 goto cleanup;
119
120 /* Checksum the plaintext. */
121 ret = krb5int_cmac_checksum(enc, ki, data, num_data, &trailer->data);
122 if (ret != 0)
123 goto cleanup;
124
125 /* Encrypt the plaintext (header | data | padding) */
126 ret = enc->encrypt(ke, ivec, data, num_data);
127 if (ret != 0)
128 goto cleanup;
129
130 cleanup:
131 krb5_k_free_key(NULL, ke);
132 krb5_k_free_key(NULL, ki);
133 return ret;
134 }
135
136 krb5_error_code
krb5int_dk_cmac_decrypt(const struct krb5_keytypes * ktp,krb5_key key,krb5_keyusage usage,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)137 krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, krb5_key key,
138 krb5_keyusage usage, const krb5_data *ivec,
139 krb5_crypto_iov *data, size_t num_data)
140 {
141 const struct krb5_enc_provider *enc = ktp->enc;
142 krb5_error_code ret;
143 krb5_crypto_iov *header, *trailer;
144 krb5_data cksum = empty_data();
145 krb5_key ke = NULL, ki = NULL;
146
147 /* E(Confounder | Plaintext | Pad) | Checksum */
148
149 /* Validate header and trailer lengths. */
150 header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
151 if (header == NULL || header->data.length != enc->block_size)
152 return KRB5_BAD_MSIZE;
153 trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
154 if (trailer == NULL || trailer->data.length != enc->block_size)
155 return KRB5_BAD_MSIZE;
156
157 /* Derive the encryption and integrity keys. */
158 ret = derive_keys(enc, key, usage, &ke, &ki);
159 if (ret != 0)
160 goto cleanup;
161
162 /* Decrypt the plaintext (header | data | padding). */
163 ret = enc->decrypt(ke, ivec, data, num_data);
164 if (ret != 0)
165 goto cleanup;
166
167 /* Verify the hash. */
168 ret = alloc_data(&cksum, enc->block_size);
169 if (ret != 0)
170 goto cleanup;
171 ret = krb5int_cmac_checksum(enc, ki, data, num_data, &cksum);
172 if (ret != 0)
173 goto cleanup;
174 if (k5_bcmp(cksum.data, trailer->data.data, enc->block_size) != 0)
175 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
176
177 cleanup:
178 krb5_k_free_key(NULL, ke);
179 krb5_k_free_key(NULL, ki);
180 zapfree(cksum.data, cksum.length);
181 return ret;
182 }
183