File Index
Files and directories
Sign in
FILE

rfc8009_aes2.c

File preview with syntax highlighting.

linux-6.19.14/crypto/krb5/rfc8009_aes2.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* rfc8009 AES Encryption with HMAC-SHA2 for Kerberos 5
  3 *
  4 * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9
 10#include <linux/slab.h>
 11#include <crypto/authenc.h>
 12#include "internal.h"
 13
 14static const struct krb5_buffer rfc8009_no_context = { .len = 0, .data = "" };
 15
 16/*
 17 * Calculate the key derivation function KDF-HMAC-SHA2(key, label, [context,] k)
 18 *
 19 *	KDF-HMAC-SHA2(key, label, [context,] k) = k-truncate(K1)
 20 *
 21 *	Using the appropriate one of:
 22 *		K1 = HMAC-SHA-256(key, 0x00000001 | label | 0x00 | k)
 23 *		K1 = HMAC-SHA-384(key, 0x00000001 | label | 0x00 | k)
 24 *		K1 = HMAC-SHA-256(key, 0x00000001 | label | 0x00 | context | k)
 25 *		K1 = HMAC-SHA-384(key, 0x00000001 | label | 0x00 | context | k)
 26 *	[rfc8009 sec 3]
 27 */
 28static int rfc8009_calc_KDF_HMAC_SHA2(const struct krb5_enctype *krb5,
 29				      const struct krb5_buffer *key,
 30				      const struct krb5_buffer *label,
 31				      const struct krb5_buffer *context,
 32				      unsigned int k,
 33				      struct krb5_buffer *result,
 34				      gfp_t gfp)
 35{
 36	struct crypto_shash *shash;
 37	struct krb5_buffer K1, data;
 38	struct shash_desc *desc;
 39	__be32 tmp;
 40	size_t bsize;
 41	void *buffer;
 42	u8 *p;
 43	int ret = -ENOMEM;
 44
 45	if (WARN_ON(result->len != k / 8))
 46		return -EINVAL;
 47
 48	shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
 49	if (IS_ERR(shash))
 50		return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
 51	ret = crypto_shash_setkey(shash, key->data, key->len);
 52	if (ret < 0)
 53		goto error_shash;
 54
 55	ret = -EINVAL;
 56	if (WARN_ON(crypto_shash_digestsize(shash) * 8 < k))
 57		goto error_shash;
 58
 59	ret = -ENOMEM;
 60	data.len = 4 + label->len + 1 + context->len + 4;
 61	bsize = krb5_shash_size(shash) +
 62		krb5_digest_size(shash) +
 63		crypto_roundup(data.len);
 64	buffer = kzalloc(bsize, GFP_NOFS);
 65	if (!buffer)
 66		goto error_shash;
 67
 68	desc = buffer;
 69	desc->tfm = shash;
 70	ret = crypto_shash_init(desc);
 71	if (ret < 0)
 72		goto error;
 73
 74	p = data.data = buffer +
 75		krb5_shash_size(shash) +
 76		krb5_digest_size(shash);
 77	*(__be32 *)p = htonl(0x00000001);
 78	p += 4;
 79	memcpy(p, label->data, label->len);
 80	p += label->len;
 81	*p++ = 0;
 82	memcpy(p, context->data, context->len);
 83	p += context->len;
 84	tmp = htonl(k);
 85	memcpy(p, &tmp, 4);
 86	p += 4;
 87
 88	ret = -EINVAL;
 89	if (WARN_ON(p - (u8 *)data.data != data.len))
 90		goto error;
 91
 92	K1.len = crypto_shash_digestsize(shash);
 93	K1.data = buffer +
 94		krb5_shash_size(shash);
 95
 96	ret = crypto_shash_finup(desc, data.data, data.len, K1.data);
 97	if (ret < 0)
 98		goto error;
 99
100	memcpy(result->data, K1.data, result->len);
101
102error:
103	kfree_sensitive(buffer);
104error_shash:
105	crypto_free_shash(shash);
106	return ret;
107}
108
109/*
110 * Calculate the pseudo-random function, PRF().
111 *
112 *	PRF = KDF-HMAC-SHA2(input-key, "prf", octet-string, 256)
113 *	PRF = KDF-HMAC-SHA2(input-key, "prf", octet-string, 384)
114 *
115 *      The "prfconstant" used in the PRF operation is the three-octet string
116 *      "prf".
117 *      [rfc8009 sec 5]
118 */
119static int rfc8009_calc_PRF(const struct krb5_enctype *krb5,
120			    const struct krb5_buffer *input_key,
121			    const struct krb5_buffer *octet_string,
122			    struct krb5_buffer *result,
123			    gfp_t gfp)
124{
125	static const struct krb5_buffer prfconstant = { 3, "prf" };
126
127	return rfc8009_calc_KDF_HMAC_SHA2(krb5, input_key, &prfconstant,
128					  octet_string, krb5->prf_len * 8,
129					  result, gfp);
130}
131
132/*
133 * Derive Ke.
134 *	Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 128)
135 *	Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 256)
136 *      [rfc8009 sec 5]
137 */
138static int rfc8009_calc_Ke(const struct krb5_enctype *krb5,
139			   const struct krb5_buffer *base_key,
140			   const struct krb5_buffer *usage_constant,
141			   struct krb5_buffer *result,
142			   gfp_t gfp)
143{
144	return rfc8009_calc_KDF_HMAC_SHA2(krb5, base_key, usage_constant,
145					  &rfc8009_no_context, krb5->key_bytes * 8,
146					  result, gfp);
147}
148
149/*
150 * Derive Kc/Ki
151 *	Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 128)
152 *	Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 128)
153 *	Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 192)
154 *	Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 192)
155 *      [rfc8009 sec 5]
156 */
157static int rfc8009_calc_Ki(const struct krb5_enctype *krb5,
158			   const struct krb5_buffer *base_key,
159			   const struct krb5_buffer *usage_constant,
160			   struct krb5_buffer *result,
161			   gfp_t gfp)
162{
163	return rfc8009_calc_KDF_HMAC_SHA2(krb5, base_key, usage_constant,
164					  &rfc8009_no_context, krb5->cksum_len * 8,
165					  result, gfp);
166}
167
168/*
169 * Apply encryption and checksumming functions to a message.  Unlike for
170 * RFC3961, for RFC8009, we have to chuck the starting IV into the hash first.
171 */
172static ssize_t rfc8009_encrypt(const struct krb5_enctype *krb5,
173			       struct crypto_aead *aead,
174			       struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
175			       size_t data_offset, size_t data_len,
176			       bool preconfounded)
177{
178	struct aead_request *req;
179	struct scatterlist bsg[2];
180	ssize_t ret, done;
181	size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
182	void *buffer;
183	u8 *iv, *ad;
184
185	if (WARN_ON(data_offset != krb5->conf_len))
186		return -EINVAL; /* Data is in wrong place */
187
188	secure_offset	= 0;
189	base_len	= krb5->conf_len + data_len;
190	pad_len		= 0;
191	secure_len	= base_len + pad_len;
192	cksum_offset	= secure_len;
193	if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
194		return -EFAULT;
195
196	bsize = krb5_aead_size(aead) +
197		krb5_aead_ivsize(aead) * 2;
198	buffer = kzalloc(bsize, GFP_NOFS);
199	if (!buffer)
200		return -ENOMEM;
201
202	req = buffer;
203	iv = buffer + krb5_aead_size(aead);
204	ad = buffer + krb5_aead_size(aead) + krb5_aead_ivsize(aead);
205
206	/* Insert the confounder into the buffer */
207	ret = -EFAULT;
208	if (!preconfounded) {
209		get_random_bytes(buffer, krb5->conf_len);
210		done = sg_pcopy_from_buffer(sg, nr_sg, buffer, krb5->conf_len,
211					    secure_offset);
212		if (done != krb5->conf_len)
213			goto error;
214	}
215
216	/* We may need to pad out to the crypto blocksize. */
217	if (pad_len) {
218		done = sg_zero_buffer(sg, nr_sg, pad_len, data_offset + data_len);
219		if (done != pad_len)
220			goto error;
221	}
222
223	/* We need to include the starting IV in the hash. */
224	sg_init_table(bsg, 2);
225	sg_set_buf(&bsg[0], ad, krb5_aead_ivsize(aead));
226	sg_chain(bsg, 2, sg);
227
228	/* Hash and encrypt the message. */
229	aead_request_set_tfm(req, aead);
230	aead_request_set_callback(req, 0, NULL, NULL);
231	aead_request_set_ad(req, krb5_aead_ivsize(aead));
232	aead_request_set_crypt(req, bsg, bsg, secure_len, iv);
233	ret = crypto_aead_encrypt(req);
234	if (ret < 0)
235		goto error;
236
237	ret = secure_len + krb5->cksum_len;
238
239error:
240	kfree_sensitive(buffer);
241	return ret;
242}
243
244/*
245 * Apply decryption and checksumming functions to a message.  Unlike for
246 * RFC3961, for RFC8009, we have to chuck the starting IV into the hash first.
247 *
248 * The offset and length are updated to reflect the actual content of the
249 * encrypted region.
250 */
251static int rfc8009_decrypt(const struct krb5_enctype *krb5,
252			   struct crypto_aead *aead,
253			   struct scatterlist *sg, unsigned int nr_sg,
254			   size_t *_offset, size_t *_len)
255{
256	struct aead_request *req;
257	struct scatterlist bsg[2];
258	size_t bsize;
259	void *buffer;
260	int ret;
261	u8 *iv, *ad;
262
263	if (WARN_ON(*_offset != 0))
264		return -EINVAL; /* Can't set offset on aead */
265
266	if (*_len < krb5->conf_len + krb5->cksum_len)
267		return -EPROTO;
268
269	bsize = krb5_aead_size(aead) +
270		krb5_aead_ivsize(aead) * 2;
271	buffer = kzalloc(bsize, GFP_NOFS);
272	if (!buffer)
273		return -ENOMEM;
274
275	req = buffer;
276	iv = buffer + krb5_aead_size(aead);
277	ad = buffer + krb5_aead_size(aead) + krb5_aead_ivsize(aead);
278
279	/* We need to include the starting IV in the hash. */
280	sg_init_table(bsg, 2);
281	sg_set_buf(&bsg[0], ad, krb5_aead_ivsize(aead));
282	sg_chain(bsg, 2, sg);
283
284	/* Decrypt the message and verify its checksum. */
285	aead_request_set_tfm(req, aead);
286	aead_request_set_callback(req, 0, NULL, NULL);
287	aead_request_set_ad(req, krb5_aead_ivsize(aead));
288	aead_request_set_crypt(req, bsg, bsg, *_len, iv);
289	ret = crypto_aead_decrypt(req);
290	if (ret < 0)
291		goto error;
292
293	/* Adjust the boundaries of the data. */
294	*_offset += krb5->conf_len;
295	*_len -= krb5->conf_len + krb5->cksum_len;
296	ret = 0;
297
298error:
299	kfree_sensitive(buffer);
300	return ret;
301}
302
303static const struct krb5_crypto_profile rfc8009_crypto_profile = {
304	.calc_PRF		= rfc8009_calc_PRF,
305	.calc_Kc		= rfc8009_calc_Ki,
306	.calc_Ke		= rfc8009_calc_Ke,
307	.calc_Ki		= rfc8009_calc_Ki,
308	.derive_encrypt_keys	= authenc_derive_encrypt_keys,
309	.load_encrypt_keys	= authenc_load_encrypt_keys,
310	.derive_checksum_key	= rfc3961_derive_checksum_key,
311	.load_checksum_key	= rfc3961_load_checksum_key,
312	.encrypt		= rfc8009_encrypt,
313	.decrypt		= rfc8009_decrypt,
314	.get_mic		= rfc3961_get_mic,
315	.verify_mic		= rfc3961_verify_mic,
316};
317
318const struct krb5_enctype krb5_aes128_cts_hmac_sha256_128 = {
319	.etype		= KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
320	.ctype		= KRB5_CKSUMTYPE_HMAC_SHA256_128_AES128,
321	.name		= "aes128-cts-hmac-sha256-128",
322	.encrypt_name	= "authenc(hmac(sha256),cts(cbc(aes)))",
323	.cksum_name	= "hmac(sha256)",
324	.hash_name	= "sha256",
325	.derivation_enc	= "cts(cbc(aes))",
326	.key_bytes	= 16,
327	.key_len	= 16,
328	.Kc_len		= 16,
329	.Ke_len		= 16,
330	.Ki_len		= 16,
331	.block_len	= 16,
332	.conf_len	= 16,
333	.cksum_len	= 16,
334	.hash_len	= 20,
335	.prf_len	= 32,
336	.keyed_cksum	= true,
337	.random_to_key	= NULL, /* Identity */
338	.profile	= &rfc8009_crypto_profile,
339};
340
341const struct krb5_enctype krb5_aes256_cts_hmac_sha384_192 = {
342	.etype		= KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
343	.ctype		= KRB5_CKSUMTYPE_HMAC_SHA384_192_AES256,
344	.name		= "aes256-cts-hmac-sha384-192",
345	.encrypt_name	= "authenc(hmac(sha384),cts(cbc(aes)))",
346	.cksum_name	= "hmac(sha384)",
347	.hash_name	= "sha384",
348	.derivation_enc	= "cts(cbc(aes))",
349	.key_bytes	= 32,
350	.key_len	= 32,
351	.Kc_len		= 24,
352	.Ke_len		= 32,
353	.Ki_len		= 24,
354	.block_len	= 16,
355	.conf_len	= 16,
356	.cksum_len	= 24,
357	.hash_len	= 20,
358	.prf_len	= 48,
359	.keyed_cksum	= true,
360	.random_to_key	= NULL, /* Identity */
361	.profile	= &rfc8009_crypto_profile,
362};
~/ Read-only file preview.