Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * echainiv: Encrypted Chain IV Generator
0004  *
0005  * This generator generates an IV based on a sequence number by multiplying
0006  * it with a salt and then encrypting it with the same key as used to encrypt
0007  * the plain text.  This algorithm requires that the block size be equal
0008  * to the IV size.  It is mainly useful for CBC.
0009  *
0010  * This generator can only be used by algorithms where authentication
0011  * is performed after encryption (i.e., authenc).
0012  *
0013  * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
0014  */
0015 
0016 #include <crypto/internal/geniv.h>
0017 #include <crypto/scatterwalk.h>
0018 #include <crypto/skcipher.h>
0019 #include <linux/err.h>
0020 #include <linux/init.h>
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/slab.h>
0024 #include <linux/string.h>
0025 
0026 static int echainiv_encrypt(struct aead_request *req)
0027 {
0028     struct crypto_aead *geniv = crypto_aead_reqtfm(req);
0029     struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
0030     struct aead_request *subreq = aead_request_ctx(req);
0031     __be64 nseqno;
0032     u64 seqno;
0033     u8 *info;
0034     unsigned int ivsize = crypto_aead_ivsize(geniv);
0035     int err;
0036 
0037     if (req->cryptlen < ivsize)
0038         return -EINVAL;
0039 
0040     aead_request_set_tfm(subreq, ctx->child);
0041 
0042     info = req->iv;
0043 
0044     if (req->src != req->dst) {
0045         SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
0046 
0047         skcipher_request_set_sync_tfm(nreq, ctx->sknull);
0048         skcipher_request_set_callback(nreq, req->base.flags,
0049                           NULL, NULL);
0050         skcipher_request_set_crypt(nreq, req->src, req->dst,
0051                        req->assoclen + req->cryptlen,
0052                        NULL);
0053 
0054         err = crypto_skcipher_encrypt(nreq);
0055         if (err)
0056             return err;
0057     }
0058 
0059     aead_request_set_callback(subreq, req->base.flags,
0060                   req->base.complete, req->base.data);
0061     aead_request_set_crypt(subreq, req->dst, req->dst,
0062                    req->cryptlen, info);
0063     aead_request_set_ad(subreq, req->assoclen);
0064 
0065     memcpy(&nseqno, info + ivsize - 8, 8);
0066     seqno = be64_to_cpu(nseqno);
0067     memset(info, 0, ivsize);
0068 
0069     scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
0070 
0071     do {
0072         u64 a;
0073 
0074         memcpy(&a, ctx->salt + ivsize - 8, 8);
0075 
0076         a |= 1;
0077         a *= seqno;
0078 
0079         memcpy(info + ivsize - 8, &a, 8);
0080     } while ((ivsize -= 8));
0081 
0082     return crypto_aead_encrypt(subreq);
0083 }
0084 
0085 static int echainiv_decrypt(struct aead_request *req)
0086 {
0087     struct crypto_aead *geniv = crypto_aead_reqtfm(req);
0088     struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
0089     struct aead_request *subreq = aead_request_ctx(req);
0090     crypto_completion_t compl;
0091     void *data;
0092     unsigned int ivsize = crypto_aead_ivsize(geniv);
0093 
0094     if (req->cryptlen < ivsize)
0095         return -EINVAL;
0096 
0097     aead_request_set_tfm(subreq, ctx->child);
0098 
0099     compl = req->base.complete;
0100     data = req->base.data;
0101 
0102     aead_request_set_callback(subreq, req->base.flags, compl, data);
0103     aead_request_set_crypt(subreq, req->src, req->dst,
0104                    req->cryptlen - ivsize, req->iv);
0105     aead_request_set_ad(subreq, req->assoclen + ivsize);
0106 
0107     scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
0108 
0109     return crypto_aead_decrypt(subreq);
0110 }
0111 
0112 static int echainiv_aead_create(struct crypto_template *tmpl,
0113                 struct rtattr **tb)
0114 {
0115     struct aead_instance *inst;
0116     int err;
0117 
0118     inst = aead_geniv_alloc(tmpl, tb);
0119 
0120     if (IS_ERR(inst))
0121         return PTR_ERR(inst);
0122 
0123     err = -EINVAL;
0124     if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize)
0125         goto free_inst;
0126 
0127     inst->alg.encrypt = echainiv_encrypt;
0128     inst->alg.decrypt = echainiv_decrypt;
0129 
0130     inst->alg.init = aead_init_geniv;
0131     inst->alg.exit = aead_exit_geniv;
0132 
0133     inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
0134     inst->alg.base.cra_ctxsize += inst->alg.ivsize;
0135 
0136     err = aead_register_instance(tmpl, inst);
0137     if (err) {
0138 free_inst:
0139         inst->free(inst);
0140     }
0141     return err;
0142 }
0143 
0144 static struct crypto_template echainiv_tmpl = {
0145     .name = "echainiv",
0146     .create = echainiv_aead_create,
0147     .module = THIS_MODULE,
0148 };
0149 
0150 static int __init echainiv_module_init(void)
0151 {
0152     return crypto_register_template(&echainiv_tmpl);
0153 }
0154 
0155 static void __exit echainiv_module_exit(void)
0156 {
0157     crypto_unregister_template(&echainiv_tmpl);
0158 }
0159 
0160 subsys_initcall(echainiv_module_init);
0161 module_exit(echainiv_module_exit);
0162 
0163 MODULE_LICENSE("GPL");
0164 MODULE_DESCRIPTION("Encrypted Chain IV Generator");
0165 MODULE_ALIAS_CRYPTO("echainiv");