Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * echainiv: Encrypted Chain IV Generator
4 : : *
5 : : * This generator generates an IV based on a sequence number by multiplying
6 : : * it with a salt and then encrypting it with the same key as used to encrypt
7 : : * the plain text. This algorithm requires that the block size be equal
8 : : * to the IV size. It is mainly useful for CBC.
9 : : *
10 : : * This generator can only be used by algorithms where authentication
11 : : * is performed after encryption (i.e., authenc).
12 : : *
13 : : * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
14 : : */
15 : :
16 : : #include <crypto/internal/geniv.h>
17 : : #include <crypto/scatterwalk.h>
18 : : #include <crypto/skcipher.h>
19 : : #include <linux/err.h>
20 : : #include <linux/init.h>
21 : : #include <linux/kernel.h>
22 : : #include <linux/module.h>
23 : : #include <linux/slab.h>
24 : : #include <linux/string.h>
25 : :
26 : 0 : static int echainiv_encrypt(struct aead_request *req)
27 : : {
28 [ # # ]: 0 : struct crypto_aead *geniv = crypto_aead_reqtfm(req);
29 [ # # ]: 0 : struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
30 [ # # ]: 0 : struct aead_request *subreq = aead_request_ctx(req);
31 : 0 : __be64 nseqno;
32 : 0 : u64 seqno;
33 : 0 : u8 *info;
34 [ # # ]: 0 : unsigned int ivsize = crypto_aead_ivsize(geniv);
35 : 0 : int err;
36 : :
37 [ # # ]: 0 : if (req->cryptlen < ivsize)
38 : : return -EINVAL;
39 : :
40 [ # # ]: 0 : aead_request_set_tfm(subreq, ctx->child);
41 : :
42 : 0 : info = req->iv;
43 : :
44 [ # # ]: 0 : if (req->src != req->dst) {
45 : 0 : SYNC_SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
46 : :
47 : 0 : skcipher_request_set_sync_tfm(nreq, ctx->sknull);
48 : 0 : skcipher_request_set_callback(nreq, req->base.flags,
49 : : NULL, NULL);
50 : 0 : skcipher_request_set_crypt(nreq, req->src, req->dst,
51 : 0 : req->assoclen + req->cryptlen,
52 : : NULL);
53 : :
54 : 0 : err = crypto_skcipher_encrypt(nreq);
55 [ # # ]: 0 : if (err)
56 : 0 : return err;
57 : : }
58 : :
59 : 0 : aead_request_set_callback(subreq, req->base.flags,
60 : : req->base.complete, req->base.data);
61 : 0 : aead_request_set_crypt(subreq, req->dst, req->dst,
62 : : req->cryptlen, info);
63 : 0 : aead_request_set_ad(subreq, req->assoclen);
64 : :
65 : 0 : memcpy(&nseqno, info + ivsize - 8, 8);
66 : 0 : seqno = be64_to_cpu(nseqno);
67 : 0 : memset(info, 0, ivsize);
68 : :
69 : 0 : scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
70 : :
71 : 0 : do {
72 : 0 : u64 a;
73 : :
74 : 0 : memcpy(&a, ctx->salt + ivsize - 8, 8);
75 : :
76 : 0 : a |= 1;
77 : 0 : a *= seqno;
78 : :
79 : 0 : memcpy(info + ivsize - 8, &a, 8);
80 [ # # ]: 0 : } while ((ivsize -= 8));
81 : :
82 : 0 : return crypto_aead_encrypt(subreq);
83 : : }
84 : :
85 : 0 : static int echainiv_decrypt(struct aead_request *req)
86 : : {
87 [ # # ]: 0 : struct crypto_aead *geniv = crypto_aead_reqtfm(req);
88 [ # # ]: 0 : struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
89 [ # # ]: 0 : struct aead_request *subreq = aead_request_ctx(req);
90 : 0 : crypto_completion_t compl;
91 : 0 : void *data;
92 [ # # ]: 0 : unsigned int ivsize = crypto_aead_ivsize(geniv);
93 : :
94 [ # # ]: 0 : if (req->cryptlen < ivsize)
95 : : return -EINVAL;
96 : :
97 : 0 : aead_request_set_tfm(subreq, ctx->child);
98 : :
99 : 0 : compl = req->base.complete;
100 : 0 : data = req->base.data;
101 : :
102 : 0 : aead_request_set_callback(subreq, req->base.flags, compl, data);
103 : 0 : aead_request_set_crypt(subreq, req->src, req->dst,
104 : : req->cryptlen - ivsize, req->iv);
105 : 0 : aead_request_set_ad(subreq, req->assoclen + ivsize);
106 : :
107 : 0 : scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
108 : :
109 : 0 : return crypto_aead_decrypt(subreq);
110 : : }
111 : :
112 : 0 : static int echainiv_aead_create(struct crypto_template *tmpl,
113 : : struct rtattr **tb)
114 : : {
115 : 0 : struct aead_instance *inst;
116 : 0 : int err;
117 : :
118 : 0 : inst = aead_geniv_alloc(tmpl, tb, 0, 0);
119 : :
120 [ # # ]: 0 : if (IS_ERR(inst))
121 : 0 : return PTR_ERR(inst);
122 : :
123 : 0 : err = -EINVAL;
124 [ # # # # ]: 0 : if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize)
125 : 0 : goto free_inst;
126 : :
127 : 0 : inst->alg.encrypt = echainiv_encrypt;
128 : 0 : inst->alg.decrypt = echainiv_decrypt;
129 : :
130 : 0 : inst->alg.init = aead_init_geniv;
131 : 0 : inst->alg.exit = aead_exit_geniv;
132 : :
133 : 0 : inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
134 : 0 : inst->alg.base.cra_ctxsize += inst->alg.ivsize;
135 : :
136 : 0 : err = aead_register_instance(tmpl, inst);
137 [ # # ]: 0 : if (err) {
138 : 0 : free_inst:
139 : 0 : inst->free(inst);
140 : : }
141 : : return err;
142 : : }
143 : :
144 : : static struct crypto_template echainiv_tmpl = {
145 : : .name = "echainiv",
146 : : .create = echainiv_aead_create,
147 : : .module = THIS_MODULE,
148 : : };
149 : :
150 : 30 : static int __init echainiv_module_init(void)
151 : : {
152 : 30 : return crypto_register_template(&echainiv_tmpl);
153 : : }
154 : :
155 : 0 : static void __exit echainiv_module_exit(void)
156 : : {
157 : 0 : crypto_unregister_template(&echainiv_tmpl);
158 : 0 : }
159 : :
160 : : subsys_initcall(echainiv_module_init);
161 : : module_exit(echainiv_module_exit);
162 : :
163 : : MODULE_LICENSE("GPL");
164 : : MODULE_DESCRIPTION("Encrypted Chain IV Generator");
165 : : MODULE_ALIAS_CRYPTO("echainiv");
|