]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - crypto/pcbc.c
block: provide plug based way of signaling forced no-wait semantics
[mirror_ubuntu-jammy-kernel.git] / crypto / pcbc.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
91652be5
DH
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>
91652be5
DH
10 */
11
6650c4de 12#include <crypto/algapi.h>
043a4400 13#include <crypto/internal/skcipher.h>
91652be5
DH
14#include <linux/err.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
91652be5 18
043a4400
HX
19static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
20 struct skcipher_walk *walk,
d0b9007a 21 struct crypto_cipher *tfm)
91652be5 22{
91652be5
DH
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;
251b7aea 27 u8 * const iv = walk->iv;
91652be5
DH
28
29 do {
d0b9007a 30 crypto_xor(iv, src, bsize);
043a4400 31 crypto_cipher_encrypt_one(tfm, dst, iv);
45fe93df 32 crypto_xor_cpy(iv, dst, src, bsize);
91652be5
DH
33
34 src += bsize;
35 dst += bsize;
36 } while ((nbytes -= bsize) >= bsize);
37
38 return nbytes;
39}
40
043a4400
HX
41static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
42 struct skcipher_walk *walk,
d0b9007a 43 struct crypto_cipher *tfm)
91652be5 44{
91652be5
DH
45 int bsize = crypto_cipher_blocksize(tfm);
46 unsigned int nbytes = walk->nbytes;
47 u8 *src = walk->src.virt.addr;
251b7aea 48 u8 * const iv = walk->iv;
6650c4de 49 u8 tmpbuf[MAX_CIPHER_BLOCKSIZE];
91652be5
DH
50
51 do {
52 memcpy(tmpbuf, src, bsize);
d0b9007a 53 crypto_xor(iv, src, bsize);
043a4400 54 crypto_cipher_encrypt_one(tfm, src, iv);
45fe93df 55 crypto_xor_cpy(iv, tmpbuf, src, bsize);
91652be5
DH
56
57 src += bsize;
58 } while ((nbytes -= bsize) >= bsize);
59
91652be5
DH
60 return nbytes;
61}
62
043a4400 63static int crypto_pcbc_encrypt(struct skcipher_request *req)
91652be5 64{
043a4400 65 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0be487ba 66 struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
043a4400
HX
67 struct skcipher_walk walk;
68 unsigned int nbytes;
91652be5
DH
69 int err;
70
043a4400 71 err = skcipher_walk_virt(&walk, req, false);
91652be5
DH
72
73 while ((nbytes = walk.nbytes)) {
74 if (walk.src.virt.addr == walk.dst.virt.addr)
043a4400 75 nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
0be487ba 76 cipher);
91652be5 77 else
043a4400 78 nbytes = crypto_pcbc_encrypt_segment(req, &walk,
0be487ba 79 cipher);
043a4400 80 err = skcipher_walk_done(&walk, nbytes);
91652be5
DH
81 }
82
83 return err;
84}
85
043a4400
HX
86static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
87 struct skcipher_walk *walk,
d0b9007a 88 struct crypto_cipher *tfm)
91652be5 89{
91652be5
DH
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;
251b7aea 94 u8 * const iv = walk->iv;
91652be5
DH
95
96 do {
043a4400 97 crypto_cipher_decrypt_one(tfm, dst, src);
d0b9007a 98 crypto_xor(dst, iv, bsize);
45fe93df 99 crypto_xor_cpy(iv, dst, src, bsize);
91652be5
DH
100
101 src += bsize;
102 dst += bsize;
103 } while ((nbytes -= bsize) >= bsize);
104
91652be5
DH
105 return nbytes;
106}
107
043a4400
HX
108static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
109 struct skcipher_walk *walk,
d0b9007a 110 struct crypto_cipher *tfm)
91652be5 111{
91652be5
DH
112 int bsize = crypto_cipher_blocksize(tfm);
113 unsigned int nbytes = walk->nbytes;
114 u8 *src = walk->src.virt.addr;
251b7aea 115 u8 * const iv = walk->iv;
6650c4de 116 u8 tmpbuf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(u32));
91652be5
DH
117
118 do {
119 memcpy(tmpbuf, src, bsize);
043a4400 120 crypto_cipher_decrypt_one(tfm, src, src);
d0b9007a 121 crypto_xor(src, iv, bsize);
45fe93df 122 crypto_xor_cpy(iv, src, tmpbuf, bsize);
91652be5
DH
123
124 src += bsize;
125 } while ((nbytes -= bsize) >= bsize);
126
91652be5
DH
127 return nbytes;
128}
129
043a4400 130static int crypto_pcbc_decrypt(struct skcipher_request *req)
91652be5 131{
043a4400 132 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0be487ba 133 struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
043a4400
HX
134 struct skcipher_walk walk;
135 unsigned int nbytes;
91652be5
DH
136 int err;
137
043a4400 138 err = skcipher_walk_virt(&walk, req, false);
91652be5
DH
139
140 while ((nbytes = walk.nbytes)) {
141 if (walk.src.virt.addr == walk.dst.virt.addr)
043a4400 142 nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
0be487ba 143 cipher);
91652be5 144 else
043a4400 145 nbytes = crypto_pcbc_decrypt_segment(req, &walk,
0be487ba 146 cipher);
043a4400 147 err = skcipher_walk_done(&walk, nbytes);
91652be5
DH
148 }
149
150 return err;
151}
152
043a4400 153static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
91652be5 154{
043a4400 155 struct skcipher_instance *inst;
ebc610e5
HX
156 int err;
157
b3c16bfc 158 inst = skcipher_alloc_instance_simple(tmpl, tb);
0be487ba
EB
159 if (IS_ERR(inst))
160 return PTR_ERR(inst);
91652be5 161
043a4400
HX
162 inst->alg.encrypt = crypto_pcbc_encrypt;
163 inst->alg.decrypt = crypto_pcbc_decrypt;
91652be5 164
043a4400
HX
165 err = skcipher_register_instance(tmpl, inst);
166 if (err)
0be487ba 167 inst->free(inst);
b3c16bfc 168
043a4400 169 return err;
91652be5
DH
170}
171
172static struct crypto_template crypto_pcbc_tmpl = {
173 .name = "pcbc",
043a4400 174 .create = crypto_pcbc_create,
91652be5
DH
175 .module = THIS_MODULE,
176};
177
178static int __init crypto_pcbc_module_init(void)
179{
180 return crypto_register_template(&crypto_pcbc_tmpl);
181}
182
183static void __exit crypto_pcbc_module_exit(void)
184{
185 crypto_unregister_template(&crypto_pcbc_tmpl);
186}
187
c4741b23 188subsys_initcall(crypto_pcbc_module_init);
91652be5
DH
189module_exit(crypto_pcbc_module_exit);
190
191MODULE_LICENSE("GPL");
0be487ba 192MODULE_DESCRIPTION("PCBC block cipher mode of operation");
4943ba16 193MODULE_ALIAS_CRYPTO("pcbc");