Merge tag 'meminit-v5.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[platform/kernel/linux-starfive.git] / crypto / pcbc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * PCBC: Propagating Cipher Block Chaining mode
4  *
5  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
6  * Written by David Howells (dhowells@redhat.com)
7  *
8  * Derived from cbc.c
9  * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
10  */
11
12 #include <crypto/algapi.h>
13 #include <crypto/internal/skcipher.h>
14 #include <linux/err.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18
19 static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
20                                        struct skcipher_walk *walk,
21                                        struct crypto_cipher *tfm)
22 {
23         int bsize = crypto_cipher_blocksize(tfm);
24         unsigned int nbytes = walk->nbytes;
25         u8 *src = walk->src.virt.addr;
26         u8 *dst = walk->dst.virt.addr;
27         u8 * const iv = walk->iv;
28
29         do {
30                 crypto_xor(iv, src, bsize);
31                 crypto_cipher_encrypt_one(tfm, dst, iv);
32                 crypto_xor_cpy(iv, dst, src, bsize);
33
34                 src += bsize;
35                 dst += bsize;
36         } while ((nbytes -= bsize) >= bsize);
37
38         return nbytes;
39 }
40
41 static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
42                                        struct skcipher_walk *walk,
43                                        struct crypto_cipher *tfm)
44 {
45         int bsize = crypto_cipher_blocksize(tfm);
46         unsigned int nbytes = walk->nbytes;
47         u8 *src = walk->src.virt.addr;
48         u8 * const iv = walk->iv;
49         u8 tmpbuf[MAX_CIPHER_BLOCKSIZE];
50
51         do {
52                 memcpy(tmpbuf, src, bsize);
53                 crypto_xor(iv, src, bsize);
54                 crypto_cipher_encrypt_one(tfm, src, iv);
55                 crypto_xor_cpy(iv, tmpbuf, src, bsize);
56
57                 src += bsize;
58         } while ((nbytes -= bsize) >= bsize);
59
60         return nbytes;
61 }
62
63 static int crypto_pcbc_encrypt(struct skcipher_request *req)
64 {
65         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
66         struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
67         struct skcipher_walk walk;
68         unsigned int nbytes;
69         int err;
70
71         err = skcipher_walk_virt(&walk, req, false);
72
73         while ((nbytes = walk.nbytes)) {
74                 if (walk.src.virt.addr == walk.dst.virt.addr)
75                         nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
76                                                              cipher);
77                 else
78                         nbytes = crypto_pcbc_encrypt_segment(req, &walk,
79                                                              cipher);
80                 err = skcipher_walk_done(&walk, nbytes);
81         }
82
83         return err;
84 }
85
86 static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
87                                        struct skcipher_walk *walk,
88                                        struct crypto_cipher *tfm)
89 {
90         int bsize = crypto_cipher_blocksize(tfm);
91         unsigned int nbytes = walk->nbytes;
92         u8 *src = walk->src.virt.addr;
93         u8 *dst = walk->dst.virt.addr;
94         u8 * const iv = walk->iv;
95
96         do {
97                 crypto_cipher_decrypt_one(tfm, dst, src);
98                 crypto_xor(dst, iv, bsize);
99                 crypto_xor_cpy(iv, dst, src, bsize);
100
101                 src += bsize;
102                 dst += bsize;
103         } while ((nbytes -= bsize) >= bsize);
104
105         return nbytes;
106 }
107
108 static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
109                                        struct skcipher_walk *walk,
110                                        struct crypto_cipher *tfm)
111 {
112         int bsize = crypto_cipher_blocksize(tfm);
113         unsigned int nbytes = walk->nbytes;
114         u8 *src = walk->src.virt.addr;
115         u8 * const iv = walk->iv;
116         u8 tmpbuf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(u32));
117
118         do {
119                 memcpy(tmpbuf, src, bsize);
120                 crypto_cipher_decrypt_one(tfm, src, src);
121                 crypto_xor(src, iv, bsize);
122                 crypto_xor_cpy(iv, src, tmpbuf, bsize);
123
124                 src += bsize;
125         } while ((nbytes -= bsize) >= bsize);
126
127         return nbytes;
128 }
129
130 static int crypto_pcbc_decrypt(struct skcipher_request *req)
131 {
132         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
133         struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
134         struct skcipher_walk walk;
135         unsigned int nbytes;
136         int err;
137
138         err = skcipher_walk_virt(&walk, req, false);
139
140         while ((nbytes = walk.nbytes)) {
141                 if (walk.src.virt.addr == walk.dst.virt.addr)
142                         nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
143                                                              cipher);
144                 else
145                         nbytes = crypto_pcbc_decrypt_segment(req, &walk,
146                                                              cipher);
147                 err = skcipher_walk_done(&walk, nbytes);
148         }
149
150         return err;
151 }
152
153 static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
154 {
155         struct skcipher_instance *inst;
156         struct crypto_alg *alg;
157         int err;
158
159         inst = skcipher_alloc_instance_simple(tmpl, tb, &alg);
160         if (IS_ERR(inst))
161                 return PTR_ERR(inst);
162
163         inst->alg.encrypt = crypto_pcbc_encrypt;
164         inst->alg.decrypt = crypto_pcbc_decrypt;
165
166         err = skcipher_register_instance(tmpl, inst);
167         if (err)
168                 inst->free(inst);
169         crypto_mod_put(alg);
170         return err;
171 }
172
173 static struct crypto_template crypto_pcbc_tmpl = {
174         .name = "pcbc",
175         .create = crypto_pcbc_create,
176         .module = THIS_MODULE,
177 };
178
179 static int __init crypto_pcbc_module_init(void)
180 {
181         return crypto_register_template(&crypto_pcbc_tmpl);
182 }
183
184 static void __exit crypto_pcbc_module_exit(void)
185 {
186         crypto_unregister_template(&crypto_pcbc_tmpl);
187 }
188
189 subsys_initcall(crypto_pcbc_module_init);
190 module_exit(crypto_pcbc_module_exit);
191
192 MODULE_LICENSE("GPL");
193 MODULE_DESCRIPTION("PCBC block cipher mode of operation");
194 MODULE_ALIAS_CRYPTO("pcbc");