Back to home page

LXR

 
 

    


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