1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * AEAD wrapper for Kerberos 5 RFC3961 simplified profile. 4 * 5 * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. 6 * Written by David Howells (dhowells@redhat.com) 7 * 8 * Derived from authenc: 9 * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au> 10 */ 11 12 #include <crypto/internal/aead.h> 13 #include <crypto/internal/hash.h> 14 #include <crypto/internal/skcipher.h> 15 #include <crypto/authenc.h> 16 #include <crypto/scatterwalk.h> 17 #include <linux/err.h> 18 #include <linux/init.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/rtnetlink.h> 22 #include <linux/slab.h> 23 #include <linux/spinlock.h> 24 25 struct krb5enc_instance_ctx { 26 struct crypto_ahash_spawn auth; 27 struct crypto_skcipher_spawn enc; 28 unsigned int reqoff; 29 }; 30 31 struct krb5enc_ctx { 32 struct crypto_ahash *auth; 33 struct crypto_skcipher *enc; 34 }; 35 36 struct krb5enc_request_ctx { 37 struct scatterlist src[2]; 38 struct scatterlist dst[2]; 39 char tail[]; 40 }; 41 42 static void krb5enc_request_complete(struct aead_request *req, int err) 43 { 44 if (err != -EINPROGRESS) 45 aead_request_complete(req, err); 46 } 47 48 /** 49 * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob. 50 * @keys: Where to put the key sizes and pointers 51 * @key: Encoded key material 52 * @keylen: Amount of key material 53 * 54 * Decode the key blob we're given. It starts with an rtattr that indicates 55 * the format and the length. Format CRYPTO_AUTHENC_KEYA_PARAM is: 56 * 57 * rtattr || __be32 enckeylen || authkey || enckey 58 * 59 * Note that the rtattr is in cpu-endian form, unlike enckeylen. This must be 60 * handled correctly in static testmgr data. 61 */ 62 int crypto_krb5enc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key, 63 unsigned int keylen) 64 { 65 struct rtattr *rta = (struct rtattr *)key; 66 struct crypto_authenc_key_param *param; 67 68 if (!RTA_OK(rta, keylen)) 69 return -EINVAL; 70 if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) 71 return -EINVAL; 72 73 /* 74 * RTA_OK() didn't align the rtattr's payload when validating that it 75 * fits in the buffer. Yet, the keys should start on the next 4-byte 76 * aligned boundary. To avoid confusion, require that the rtattr 77 * payload be exactly the param struct, which has a 4-byte aligned size. 78 */ 79 if (RTA_PAYLOAD(rta) != sizeof(*param)) 80 return -EINVAL; 81 BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO); 82 83 param = RTA_DATA(rta); 84 keys->enckeylen = be32_to_cpu(param->enckeylen); 85 86 key += rta->rta_len; 87 keylen -= rta->rta_len; 88 89 if (keylen < keys->enckeylen) 90 return -EINVAL; 91 92 keys->authkeylen = keylen - keys->enckeylen; 93 keys->authkey = key; 94 keys->enckey = key + keys->authkeylen; 95 return 0; 96 } 97 EXPORT_SYMBOL(crypto_krb5enc_extractkeys); 98 99 static int krb5enc_setkey(struct crypto_aead *krb5enc, const u8 *key, 100 unsigned int keylen) 101 { 102 struct crypto_authenc_keys keys; 103 struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc); 104 struct crypto_skcipher *enc = ctx->enc; 105 struct crypto_ahash *auth = ctx->auth; 106 unsigned int flags = crypto_aead_get_flags(krb5enc); 107 int err = -EINVAL; 108 109 if (crypto_krb5enc_extractkeys(&keys, key, keylen) != 0) 110 goto out; 111 112 crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); 113 crypto_ahash_set_flags(auth, flags & CRYPTO_TFM_REQ_MASK); 114 err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); 115 if (err) 116 goto out; 117 118 crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); 119 crypto_skcipher_set_flags(enc, flags & CRYPTO_TFM_REQ_MASK); 120 err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen); 121 out: 122 memzero_explicit(&keys, sizeof(keys)); 123 return err; 124 } 125 126 static void krb5enc_encrypt_done(void *data, int err) 127 { 128 struct aead_request *req = data; 129 130 krb5enc_request_complete(req, err); 131 } 132 133 /* 134 * Start the encryption of the plaintext. We skip over the associated data as 135 * that only gets included in the hash. 136 */ 137 static int krb5enc_dispatch_encrypt(struct aead_request *req, 138 unsigned int flags) 139 { 140 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 141 struct aead_instance *inst = aead_alg_instance(krb5enc); 142 struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc); 143 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 144 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 145 struct crypto_skcipher *enc = ctx->enc; 146 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 147 ictx->reqoff); 148 struct scatterlist *src, *dst; 149 150 src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen); 151 if (req->src == req->dst) 152 dst = src; 153 else 154 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); 155 156 skcipher_request_set_tfm(skreq, enc); 157 skcipher_request_set_callback(skreq, aead_request_flags(req), 158 krb5enc_encrypt_done, req); 159 skcipher_request_set_crypt(skreq, src, dst, req->cryptlen, req->iv); 160 161 return crypto_skcipher_encrypt(skreq); 162 } 163 164 /* 165 * Insert the hash into the checksum field in the destination buffer directly 166 * after the encrypted region. 167 */ 168 static void krb5enc_insert_checksum(struct aead_request *req, u8 *hash) 169 { 170 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 171 172 scatterwalk_map_and_copy(hash, req->dst, 173 req->assoclen + req->cryptlen, 174 crypto_aead_authsize(krb5enc), 1); 175 } 176 177 /* 178 * Upon completion of an asynchronous digest, transfer the hash to the checksum 179 * field. 180 */ 181 static void krb5enc_encrypt_ahash_done(void *data, int err) 182 { 183 struct aead_request *req = data; 184 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 185 struct aead_instance *inst = aead_alg_instance(krb5enc); 186 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 187 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 188 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 189 190 if (err) 191 return krb5enc_request_complete(req, err); 192 193 krb5enc_insert_checksum(req, ahreq->result); 194 195 err = krb5enc_dispatch_encrypt(req, 0); 196 if (err != -EINPROGRESS) 197 aead_request_complete(req, err); 198 } 199 200 /* 201 * Start the digest of the plaintext for encryption. In theory, this could be 202 * run in parallel with the encryption, provided the src and dst buffers don't 203 * overlap. 204 */ 205 static int krb5enc_dispatch_encrypt_hash(struct aead_request *req) 206 { 207 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 208 struct aead_instance *inst = aead_alg_instance(krb5enc); 209 struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc); 210 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 211 struct crypto_ahash *auth = ctx->auth; 212 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 213 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 214 u8 *hash = areq_ctx->tail; 215 int err; 216 217 ahash_request_set_callback(ahreq, aead_request_flags(req), 218 krb5enc_encrypt_ahash_done, req); 219 ahash_request_set_tfm(ahreq, auth); 220 ahash_request_set_crypt(ahreq, req->src, hash, req->assoclen + req->cryptlen); 221 222 err = crypto_ahash_digest(ahreq); 223 if (err) 224 return err; 225 226 krb5enc_insert_checksum(req, hash); 227 return 0; 228 } 229 230 /* 231 * Process an encryption operation. We can perform the cipher and the hash in 232 * parallel, provided the src and dst buffers are separate. 233 */ 234 static int krb5enc_encrypt(struct aead_request *req) 235 { 236 int err; 237 238 err = krb5enc_dispatch_encrypt_hash(req); 239 if (err < 0) 240 return err; 241 242 return krb5enc_dispatch_encrypt(req, aead_request_flags(req)); 243 } 244 245 static int krb5enc_verify_hash(struct aead_request *req) 246 { 247 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 248 struct aead_instance *inst = aead_alg_instance(krb5enc); 249 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 250 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 251 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 252 unsigned int authsize = crypto_aead_authsize(krb5enc); 253 u8 *calc_hash = areq_ctx->tail; 254 u8 *msg_hash = areq_ctx->tail + authsize; 255 256 scatterwalk_map_and_copy(msg_hash, req->src, ahreq->nbytes, authsize, 0); 257 258 if (crypto_memneq(msg_hash, calc_hash, authsize)) 259 return -EBADMSG; 260 return 0; 261 } 262 263 static void krb5enc_decrypt_hash_done(void *data, int err) 264 { 265 struct aead_request *req = data; 266 267 if (err) 268 return krb5enc_request_complete(req, err); 269 270 err = krb5enc_verify_hash(req); 271 krb5enc_request_complete(req, err); 272 } 273 274 /* 275 * Dispatch the hashing of the plaintext after we've done the decryption. 276 */ 277 static int krb5enc_dispatch_decrypt_hash(struct aead_request *req) 278 { 279 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 280 struct aead_instance *inst = aead_alg_instance(krb5enc); 281 struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc); 282 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 283 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 284 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 285 struct crypto_ahash *auth = ctx->auth; 286 unsigned int authsize = crypto_aead_authsize(krb5enc); 287 u8 *hash = areq_ctx->tail; 288 int err; 289 290 ahash_request_set_tfm(ahreq, auth); 291 ahash_request_set_crypt(ahreq, req->dst, hash, 292 req->assoclen + req->cryptlen - authsize); 293 ahash_request_set_callback(ahreq, aead_request_flags(req), 294 krb5enc_decrypt_hash_done, req); 295 296 err = crypto_ahash_digest(ahreq); 297 if (err < 0) 298 return err; 299 300 return krb5enc_verify_hash(req); 301 } 302 303 /* 304 * Dispatch the decryption of the ciphertext. 305 */ 306 static int krb5enc_dispatch_decrypt(struct aead_request *req) 307 { 308 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 309 struct aead_instance *inst = aead_alg_instance(krb5enc); 310 struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc); 311 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 312 struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req); 313 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 314 ictx->reqoff); 315 unsigned int authsize = crypto_aead_authsize(krb5enc); 316 struct scatterlist *src, *dst; 317 318 src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen); 319 dst = src; 320 321 if (req->src != req->dst) 322 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); 323 324 skcipher_request_set_tfm(skreq, ctx->enc); 325 skcipher_request_set_callback(skreq, aead_request_flags(req), 326 req->base.complete, req->base.data); 327 skcipher_request_set_crypt(skreq, src, dst, 328 req->cryptlen - authsize, req->iv); 329 330 return crypto_skcipher_decrypt(skreq); 331 } 332 333 static int krb5enc_decrypt(struct aead_request *req) 334 { 335 int err; 336 337 err = krb5enc_dispatch_decrypt(req); 338 if (err < 0) 339 return err; 340 341 return krb5enc_dispatch_decrypt_hash(req); 342 } 343 344 static int krb5enc_init_tfm(struct crypto_aead *tfm) 345 { 346 struct aead_instance *inst = aead_alg_instance(tfm); 347 struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst); 348 struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm); 349 struct crypto_ahash *auth; 350 struct crypto_skcipher *enc; 351 int err; 352 353 auth = crypto_spawn_ahash(&ictx->auth); 354 if (IS_ERR(auth)) 355 return PTR_ERR(auth); 356 357 enc = crypto_spawn_skcipher(&ictx->enc); 358 err = PTR_ERR(enc); 359 if (IS_ERR(enc)) 360 goto err_free_ahash; 361 362 ctx->auth = auth; 363 ctx->enc = enc; 364 365 crypto_aead_set_reqsize( 366 tfm, 367 sizeof(struct krb5enc_request_ctx) + 368 ictx->reqoff + /* Space for two checksums */ 369 umax(sizeof(struct ahash_request) + crypto_ahash_reqsize(auth), 370 sizeof(struct skcipher_request) + crypto_skcipher_reqsize(enc))); 371 372 return 0; 373 374 err_free_ahash: 375 crypto_free_ahash(auth); 376 return err; 377 } 378 379 static void krb5enc_exit_tfm(struct crypto_aead *tfm) 380 { 381 struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm); 382 383 crypto_free_ahash(ctx->auth); 384 crypto_free_skcipher(ctx->enc); 385 } 386 387 static void krb5enc_free(struct aead_instance *inst) 388 { 389 struct krb5enc_instance_ctx *ctx = aead_instance_ctx(inst); 390 391 crypto_drop_skcipher(&ctx->enc); 392 crypto_drop_ahash(&ctx->auth); 393 kfree(inst); 394 } 395 396 /* 397 * Create an instance of a template for a specific hash and cipher pair. 398 */ 399 static int krb5enc_create(struct crypto_template *tmpl, struct rtattr **tb) 400 { 401 struct krb5enc_instance_ctx *ictx; 402 struct skcipher_alg_common *enc; 403 struct hash_alg_common *auth; 404 struct aead_instance *inst; 405 struct crypto_alg *auth_base; 406 u32 mask; 407 int err; 408 409 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 410 if (err) { 411 pr_err("attr_type failed\n"); 412 return err; 413 } 414 415 inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); 416 if (!inst) 417 return -ENOMEM; 418 ictx = aead_instance_ctx(inst); 419 420 err = crypto_grab_ahash(&ictx->auth, aead_crypto_instance(inst), 421 crypto_attr_alg_name(tb[1]), 0, mask); 422 if (err) { 423 pr_err("grab ahash failed\n"); 424 goto err_free_inst; 425 } 426 auth = crypto_spawn_ahash_alg(&ictx->auth); 427 auth_base = &auth->base; 428 429 err = crypto_grab_skcipher(&ictx->enc, aead_crypto_instance(inst), 430 crypto_attr_alg_name(tb[2]), 0, mask); 431 if (err) { 432 pr_err("grab skcipher failed\n"); 433 goto err_free_inst; 434 } 435 enc = crypto_spawn_skcipher_alg_common(&ictx->enc); 436 437 ictx->reqoff = 2 * auth->digestsize; 438 439 err = -ENAMETOOLONG; 440 if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 441 "krb5enc(%s,%s)", auth_base->cra_name, 442 enc->base.cra_name) >= 443 CRYPTO_MAX_ALG_NAME) 444 goto err_free_inst; 445 446 if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 447 "krb5enc(%s,%s)", auth_base->cra_driver_name, 448 enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 449 goto err_free_inst; 450 451 inst->alg.base.cra_priority = enc->base.cra_priority * 10 + 452 auth_base->cra_priority; 453 inst->alg.base.cra_blocksize = enc->base.cra_blocksize; 454 inst->alg.base.cra_alignmask = enc->base.cra_alignmask; 455 inst->alg.base.cra_ctxsize = sizeof(struct krb5enc_ctx); 456 457 inst->alg.ivsize = enc->ivsize; 458 inst->alg.chunksize = enc->chunksize; 459 inst->alg.maxauthsize = auth->digestsize; 460 461 inst->alg.init = krb5enc_init_tfm; 462 inst->alg.exit = krb5enc_exit_tfm; 463 464 inst->alg.setkey = krb5enc_setkey; 465 inst->alg.encrypt = krb5enc_encrypt; 466 inst->alg.decrypt = krb5enc_decrypt; 467 468 inst->free = krb5enc_free; 469 470 err = aead_register_instance(tmpl, inst); 471 if (err) { 472 pr_err("ref failed\n"); 473 goto err_free_inst; 474 } 475 476 return 0; 477 478 err_free_inst: 479 krb5enc_free(inst); 480 return err; 481 } 482 483 static struct crypto_template crypto_krb5enc_tmpl = { 484 .name = "krb5enc", 485 .create = krb5enc_create, 486 .module = THIS_MODULE, 487 }; 488 489 static int __init crypto_krb5enc_module_init(void) 490 { 491 return crypto_register_template(&crypto_krb5enc_tmpl); 492 } 493 494 static void __exit crypto_krb5enc_module_exit(void) 495 { 496 crypto_unregister_template(&crypto_krb5enc_tmpl); 497 } 498 499 subsys_initcall(crypto_krb5enc_module_init); 500 module_exit(crypto_krb5enc_module_exit); 501 502 MODULE_LICENSE("GPL"); 503 MODULE_DESCRIPTION("Simple AEAD wrapper for Kerberos 5 RFC3961"); 504 MODULE_ALIAS_CRYPTO("krb5enc"); 505