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