File Index
Files and directories
Sign in
FILE

rfc6803_camellia.c

File preview with syntax highlighting.

linux-6.19.14/crypto/krb5/rfc6803_camellia.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* rfc6803 Camellia Encryption 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 "internal.h"
 12
 13/*
 14 * Calculate the key derivation function KDF-FEEDBACK_CMAC(key, constant)
 15 *
 16 *	n = ceiling(k / 128)
 17 *	K(0) = zeros
 18 *	K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
 19 *	DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
 20 *	KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
 21 *
 22 *	[rfc6803 sec 3]
 23 */
 24static int rfc6803_calc_KDF_FEEDBACK_CMAC(const struct krb5_enctype *krb5,
 25					  const struct krb5_buffer *key,
 26					  const struct krb5_buffer *constant,
 27					  struct krb5_buffer *result,
 28					  gfp_t gfp)
 29{
 30	struct crypto_shash *shash;
 31	struct krb5_buffer K, data;
 32	struct shash_desc *desc;
 33	__be32 tmp;
 34	size_t bsize, offset, seg;
 35	void *buffer;
 36	u32 i = 0, k = result->len * 8;
 37	u8 *p;
 38	int ret = -ENOMEM;
 39
 40	shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
 41	if (IS_ERR(shash))
 42		return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
 43	ret = crypto_shash_setkey(shash, key->data, key->len);
 44	if (ret < 0)
 45		goto error_shash;
 46
 47	ret = -ENOMEM;
 48	K.len = crypto_shash_digestsize(shash);
 49	data.len = K.len + 4 + constant->len + 1 + 4;
 50	bsize = krb5_shash_size(shash) +
 51		krb5_digest_size(shash) +
 52		crypto_roundup(K.len) +
 53		crypto_roundup(data.len);
 54	buffer = kzalloc(bsize, GFP_NOFS);
 55	if (!buffer)
 56		goto error_shash;
 57
 58	desc = buffer;
 59	desc->tfm = shash;
 60
 61	K.data = buffer +
 62		krb5_shash_size(shash) +
 63		krb5_digest_size(shash);
 64	data.data = buffer +
 65		krb5_shash_size(shash) +
 66		krb5_digest_size(shash) +
 67		crypto_roundup(K.len);
 68
 69	p = data.data + K.len + 4;
 70	memcpy(p, constant->data, constant->len);
 71	p += constant->len;
 72	*p++ = 0x00;
 73	tmp = htonl(k);
 74	memcpy(p, &tmp, 4);
 75	p += 4;
 76
 77	ret = -EINVAL;
 78	if (WARN_ON(p - (u8 *)data.data != data.len))
 79		goto error;
 80
 81	offset = 0;
 82	do {
 83		i++;
 84		p = data.data;
 85		memcpy(p, K.data, K.len);
 86		p += K.len;
 87		*(__be32 *)p = htonl(i);
 88
 89		ret = crypto_shash_init(desc);
 90		if (ret < 0)
 91			goto error;
 92		ret = crypto_shash_finup(desc, data.data, data.len, K.data);
 93		if (ret < 0)
 94			goto error;
 95
 96		seg = min_t(size_t, result->len - offset, K.len);
 97		memcpy(result->data + offset, K.data, seg);
 98		offset += seg;
 99	} while (offset < result->len);
100
101error:
102	kfree_sensitive(buffer);
103error_shash:
104	crypto_free_shash(shash);
105	return ret;
106}
107
108/*
109 * Calculate the pseudo-random function, PRF().
110 *
111 *	Kp = KDF-FEEDBACK-CMAC(protocol-key, "prf")
112 *	PRF = CMAC(Kp, octet-string)
113 *      [rfc6803 sec 6]
114 */
115static int rfc6803_calc_PRF(const struct krb5_enctype *krb5,
116			    const struct krb5_buffer *protocol_key,
117			    const struct krb5_buffer *octet_string,
118			    struct krb5_buffer *result,
119			    gfp_t gfp)
120{
121	static const struct krb5_buffer prfconstant = { 3, "prf" };
122	struct crypto_shash *shash;
123	struct krb5_buffer Kp;
124	struct shash_desc *desc;
125	size_t bsize;
126	void *buffer;
127	int ret;
128
129	Kp.len = krb5->prf_len;
130
131	shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
132	if (IS_ERR(shash))
133		return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
134
135	ret = -EINVAL;
136	if (result->len != crypto_shash_digestsize(shash))
137		goto out_shash;
138
139	ret = -ENOMEM;
140	bsize = krb5_shash_size(shash) +
141		krb5_digest_size(shash) +
142		crypto_roundup(Kp.len);
143	buffer = kzalloc(bsize, GFP_NOFS);
144	if (!buffer)
145		goto out_shash;
146
147	Kp.data = buffer +
148		krb5_shash_size(shash) +
149		krb5_digest_size(shash);
150
151	ret = rfc6803_calc_KDF_FEEDBACK_CMAC(krb5, protocol_key, &prfconstant,
152					     &Kp, gfp);
153	if (ret < 0)
154		goto out;
155
156	ret = crypto_shash_setkey(shash, Kp.data, Kp.len);
157	if (ret < 0)
158		goto out;
159
160	desc = buffer;
161	desc->tfm = shash;
162	ret = crypto_shash_init(desc);
163	if (ret < 0)
164		goto out;
165
166	ret = crypto_shash_finup(desc, octet_string->data, octet_string->len, result->data);
167	if (ret < 0)
168		goto out;
169
170out:
171	kfree_sensitive(buffer);
172out_shash:
173	crypto_free_shash(shash);
174	return ret;
175}
176
177
178static const struct krb5_crypto_profile rfc6803_crypto_profile = {
179	.calc_PRF		= rfc6803_calc_PRF,
180	.calc_Kc		= rfc6803_calc_KDF_FEEDBACK_CMAC,
181	.calc_Ke		= rfc6803_calc_KDF_FEEDBACK_CMAC,
182	.calc_Ki		= rfc6803_calc_KDF_FEEDBACK_CMAC,
183	.derive_encrypt_keys	= authenc_derive_encrypt_keys,
184	.load_encrypt_keys	= authenc_load_encrypt_keys,
185	.derive_checksum_key	= rfc3961_derive_checksum_key,
186	.load_checksum_key	= rfc3961_load_checksum_key,
187	.encrypt		= krb5_aead_encrypt,
188	.decrypt		= krb5_aead_decrypt,
189	.get_mic		= rfc3961_get_mic,
190	.verify_mic		= rfc3961_verify_mic,
191};
192
193const struct krb5_enctype krb5_camellia128_cts_cmac = {
194	.etype		= KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
195	.ctype		= KRB5_CKSUMTYPE_CMAC_CAMELLIA128,
196	.name		= "camellia128-cts-cmac",
197	.encrypt_name	= "krb5enc(cmac(camellia),cts(cbc(camellia)))",
198	.cksum_name	= "cmac(camellia)",
199	.hash_name	= NULL,
200	.derivation_enc	= "cts(cbc(camellia))",
201	.key_bytes	= 16,
202	.key_len	= 16,
203	.Kc_len		= 16,
204	.Ke_len		= 16,
205	.Ki_len		= 16,
206	.block_len	= 16,
207	.conf_len	= 16,
208	.cksum_len	= 16,
209	.hash_len	= 16,
210	.prf_len	= 16,
211	.keyed_cksum	= true,
212	.random_to_key	= NULL, /* Identity */
213	.profile	= &rfc6803_crypto_profile,
214};
215
216const struct krb5_enctype krb5_camellia256_cts_cmac = {
217	.etype		= KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
218	.ctype		= KRB5_CKSUMTYPE_CMAC_CAMELLIA256,
219	.name		= "camellia256-cts-cmac",
220	.encrypt_name	= "krb5enc(cmac(camellia),cts(cbc(camellia)))",
221	.cksum_name	= "cmac(camellia)",
222	.hash_name	= NULL,
223	.derivation_enc	= "cts(cbc(camellia))",
224	.key_bytes	= 32,
225	.key_len	= 32,
226	.Kc_len		= 32,
227	.Ke_len		= 32,
228	.Ki_len		= 32,
229	.block_len	= 16,
230	.conf_len	= 16,
231	.cksum_len	= 16,
232	.hash_len	= 16,
233	.prf_len	= 16,
234	.keyed_cksum	= true,
235	.random_to_key	= NULL, /* Identity */
236	.profile	= &rfc6803_crypto_profile,
237};
~/ Read-only file preview.