1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PCBC: Propagating Cipher Block Chaining mode
5 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
6 * Written by David Howells (dhowells@redhat.com)
9 * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
12 #include <crypto/algapi.h>
13 #include <crypto/internal/cipher.h>
14 #include <crypto/internal/skcipher.h>
15 #include <linux/err.h>
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
20 static int crypto_pcbc_encrypt_segment(struct skcipher_request
*req
,
21 struct skcipher_walk
*walk
,
22 struct crypto_cipher
*tfm
)
24 int bsize
= crypto_cipher_blocksize(tfm
);
25 unsigned int nbytes
= walk
->nbytes
;
26 u8
*src
= walk
->src
.virt
.addr
;
27 u8
*dst
= walk
->dst
.virt
.addr
;
28 u8
* const iv
= walk
->iv
;
31 crypto_xor(iv
, src
, bsize
);
32 crypto_cipher_encrypt_one(tfm
, dst
, iv
);
33 crypto_xor_cpy(iv
, dst
, src
, bsize
);
37 } while ((nbytes
-= bsize
) >= bsize
);
42 static int crypto_pcbc_encrypt_inplace(struct skcipher_request
*req
,
43 struct skcipher_walk
*walk
,
44 struct crypto_cipher
*tfm
)
46 int bsize
= crypto_cipher_blocksize(tfm
);
47 unsigned int nbytes
= walk
->nbytes
;
48 u8
*src
= walk
->src
.virt
.addr
;
49 u8
* const iv
= walk
->iv
;
50 u8 tmpbuf
[MAX_CIPHER_BLOCKSIZE
];
53 memcpy(tmpbuf
, src
, bsize
);
54 crypto_xor(iv
, src
, bsize
);
55 crypto_cipher_encrypt_one(tfm
, src
, iv
);
56 crypto_xor_cpy(iv
, tmpbuf
, src
, bsize
);
59 } while ((nbytes
-= bsize
) >= bsize
);
64 static int crypto_pcbc_encrypt(struct skcipher_request
*req
)
66 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
67 struct crypto_cipher
*cipher
= skcipher_cipher_simple(tfm
);
68 struct skcipher_walk walk
;
72 err
= skcipher_walk_virt(&walk
, req
, false);
75 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
76 nbytes
= crypto_pcbc_encrypt_inplace(req
, &walk
,
79 nbytes
= crypto_pcbc_encrypt_segment(req
, &walk
,
81 err
= skcipher_walk_done(&walk
, nbytes
);
87 static int crypto_pcbc_decrypt_segment(struct skcipher_request
*req
,
88 struct skcipher_walk
*walk
,
89 struct crypto_cipher
*tfm
)
91 int bsize
= crypto_cipher_blocksize(tfm
);
92 unsigned int nbytes
= walk
->nbytes
;
93 u8
*src
= walk
->src
.virt
.addr
;
94 u8
*dst
= walk
->dst
.virt
.addr
;
95 u8
* const iv
= walk
->iv
;
98 crypto_cipher_decrypt_one(tfm
, dst
, src
);
99 crypto_xor(dst
, iv
, bsize
);
100 crypto_xor_cpy(iv
, dst
, src
, bsize
);
104 } while ((nbytes
-= bsize
) >= bsize
);
109 static int crypto_pcbc_decrypt_inplace(struct skcipher_request
*req
,
110 struct skcipher_walk
*walk
,
111 struct crypto_cipher
*tfm
)
113 int bsize
= crypto_cipher_blocksize(tfm
);
114 unsigned int nbytes
= walk
->nbytes
;
115 u8
*src
= walk
->src
.virt
.addr
;
116 u8
* const iv
= walk
->iv
;
117 u8 tmpbuf
[MAX_CIPHER_BLOCKSIZE
] __aligned(__alignof__(u32
));
120 memcpy(tmpbuf
, src
, bsize
);
121 crypto_cipher_decrypt_one(tfm
, src
, src
);
122 crypto_xor(src
, iv
, bsize
);
123 crypto_xor_cpy(iv
, src
, tmpbuf
, bsize
);
126 } while ((nbytes
-= bsize
) >= bsize
);
131 static int crypto_pcbc_decrypt(struct skcipher_request
*req
)
133 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
134 struct crypto_cipher
*cipher
= skcipher_cipher_simple(tfm
);
135 struct skcipher_walk walk
;
139 err
= skcipher_walk_virt(&walk
, req
, false);
141 while (walk
.nbytes
) {
142 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
143 nbytes
= crypto_pcbc_decrypt_inplace(req
, &walk
,
146 nbytes
= crypto_pcbc_decrypt_segment(req
, &walk
,
148 err
= skcipher_walk_done(&walk
, nbytes
);
154 static int crypto_pcbc_create(struct crypto_template
*tmpl
, struct rtattr
**tb
)
156 struct skcipher_instance
*inst
;
159 inst
= skcipher_alloc_instance_simple(tmpl
, tb
);
161 return PTR_ERR(inst
);
163 inst
->alg
.encrypt
= crypto_pcbc_encrypt
;
164 inst
->alg
.decrypt
= crypto_pcbc_decrypt
;
166 err
= skcipher_register_instance(tmpl
, inst
);
173 static struct crypto_template crypto_pcbc_tmpl
= {
175 .create
= crypto_pcbc_create
,
176 .module
= THIS_MODULE
,
179 static int __init
crypto_pcbc_module_init(void)
181 return crypto_register_template(&crypto_pcbc_tmpl
);
184 static void __exit
crypto_pcbc_module_exit(void)
186 crypto_unregister_template(&crypto_pcbc_tmpl
);
189 subsys_initcall(crypto_pcbc_module_init
);
190 module_exit(crypto_pcbc_module_exit
);
192 MODULE_LICENSE("GPL");
193 MODULE_DESCRIPTION("PCBC block cipher mode of operation");
194 MODULE_ALIAS_CRYPTO("pcbc");
195 MODULE_IMPORT_NS("CRYPTO_INTERNAL");