xref: /freebsd/crypto/krb5/src/lib/crypto/krb/enc_dk_cmac.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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