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/skcipher.h>
14 #include <linux/err.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
19 static int crypto_pcbc_encrypt_segment(struct skcipher_request
*req
,
20 struct skcipher_walk
*walk
,
21 struct crypto_cipher
*tfm
)
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
;
30 crypto_xor(iv
, src
, bsize
);
31 crypto_cipher_encrypt_one(tfm
, dst
, iv
);
32 crypto_xor_cpy(iv
, dst
, src
, bsize
);
36 } while ((nbytes
-= bsize
) >= bsize
);
41 static int crypto_pcbc_encrypt_inplace(struct skcipher_request
*req
,
42 struct skcipher_walk
*walk
,
43 struct crypto_cipher
*tfm
)
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
];
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
);
58 } while ((nbytes
-= bsize
) >= bsize
);
63 static int crypto_pcbc_encrypt(struct skcipher_request
*req
)
65 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
66 struct crypto_cipher
*cipher
= skcipher_cipher_simple(tfm
);
67 struct skcipher_walk walk
;
71 err
= skcipher_walk_virt(&walk
, req
, false);
73 while ((nbytes
= walk
.nbytes
)) {
74 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
75 nbytes
= crypto_pcbc_encrypt_inplace(req
, &walk
,
78 nbytes
= crypto_pcbc_encrypt_segment(req
, &walk
,
80 err
= skcipher_walk_done(&walk
, nbytes
);
86 static int crypto_pcbc_decrypt_segment(struct skcipher_request
*req
,
87 struct skcipher_walk
*walk
,
88 struct crypto_cipher
*tfm
)
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
;
97 crypto_cipher_decrypt_one(tfm
, dst
, src
);
98 crypto_xor(dst
, iv
, bsize
);
99 crypto_xor_cpy(iv
, dst
, src
, bsize
);
103 } while ((nbytes
-= bsize
) >= bsize
);
108 static int crypto_pcbc_decrypt_inplace(struct skcipher_request
*req
,
109 struct skcipher_walk
*walk
,
110 struct crypto_cipher
*tfm
)
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
));
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
);
125 } while ((nbytes
-= bsize
) >= bsize
);
130 static int crypto_pcbc_decrypt(struct skcipher_request
*req
)
132 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
133 struct crypto_cipher
*cipher
= skcipher_cipher_simple(tfm
);
134 struct skcipher_walk walk
;
138 err
= skcipher_walk_virt(&walk
, req
, false);
140 while ((nbytes
= walk
.nbytes
)) {
141 if (walk
.src
.virt
.addr
== walk
.dst
.virt
.addr
)
142 nbytes
= crypto_pcbc_decrypt_inplace(req
, &walk
,
145 nbytes
= crypto_pcbc_decrypt_segment(req
, &walk
,
147 err
= skcipher_walk_done(&walk
, nbytes
);
153 static int crypto_pcbc_create(struct crypto_template
*tmpl
, struct rtattr
**tb
)
155 struct skcipher_instance
*inst
;
158 inst
= skcipher_alloc_instance_simple(tmpl
, tb
);
160 return PTR_ERR(inst
);
162 inst
->alg
.encrypt
= crypto_pcbc_encrypt
;
163 inst
->alg
.decrypt
= crypto_pcbc_decrypt
;
165 err
= skcipher_register_instance(tmpl
, inst
);
172 static struct crypto_template crypto_pcbc_tmpl
= {
174 .create
= crypto_pcbc_create
,
175 .module
= THIS_MODULE
,
178 static int __init
crypto_pcbc_module_init(void)
180 return crypto_register_template(&crypto_pcbc_tmpl
);
183 static void __exit
crypto_pcbc_module_exit(void)
185 crypto_unregister_template(&crypto_pcbc_tmpl
);
188 subsys_initcall(crypto_pcbc_module_init
);
189 module_exit(crypto_pcbc_module_exit
);
191 MODULE_LICENSE("GPL");
192 MODULE_DESCRIPTION("PCBC block cipher mode of operation");
193 MODULE_ALIAS_CRYPTO("pcbc");