Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/cbc.c
26131 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* CBC: Cipher Block Chaining mode
4
*
5
* Copyright (c) 2006-2016 Herbert Xu <[email protected]>
6
*/
7
8
#include <crypto/internal/skcipher.h>
9
#include <linux/err.h>
10
#include <linux/init.h>
11
#include <linux/kernel.h>
12
#include <linux/log2.h>
13
#include <linux/module.h>
14
15
static int crypto_cbc_encrypt_segment(struct crypto_lskcipher *tfm,
16
const u8 *src, u8 *dst, unsigned nbytes,
17
u8 *iv)
18
{
19
unsigned int bsize = crypto_lskcipher_blocksize(tfm);
20
21
for (; nbytes >= bsize; src += bsize, dst += bsize, nbytes -= bsize) {
22
crypto_xor(iv, src, bsize);
23
crypto_lskcipher_encrypt(tfm, iv, dst, bsize, NULL);
24
memcpy(iv, dst, bsize);
25
}
26
27
return nbytes;
28
}
29
30
static int crypto_cbc_encrypt_inplace(struct crypto_lskcipher *tfm,
31
u8 *src, unsigned nbytes, u8 *oiv)
32
{
33
unsigned int bsize = crypto_lskcipher_blocksize(tfm);
34
u8 *iv = oiv;
35
36
if (nbytes < bsize)
37
goto out;
38
39
do {
40
crypto_xor(src, iv, bsize);
41
crypto_lskcipher_encrypt(tfm, src, src, bsize, NULL);
42
iv = src;
43
44
src += bsize;
45
} while ((nbytes -= bsize) >= bsize);
46
47
memcpy(oiv, iv, bsize);
48
49
out:
50
return nbytes;
51
}
52
53
static int crypto_cbc_encrypt(struct crypto_lskcipher *tfm, const u8 *src,
54
u8 *dst, unsigned len, u8 *iv, u32 flags)
55
{
56
struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm);
57
bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL;
58
struct crypto_lskcipher *cipher = *ctx;
59
int rem;
60
61
if (src == dst)
62
rem = crypto_cbc_encrypt_inplace(cipher, dst, len, iv);
63
else
64
rem = crypto_cbc_encrypt_segment(cipher, src, dst, len, iv);
65
66
return rem && final ? -EINVAL : rem;
67
}
68
69
static int crypto_cbc_decrypt_segment(struct crypto_lskcipher *tfm,
70
const u8 *src, u8 *dst, unsigned nbytes,
71
u8 *oiv)
72
{
73
unsigned int bsize = crypto_lskcipher_blocksize(tfm);
74
const u8 *iv = oiv;
75
76
if (nbytes < bsize)
77
goto out;
78
79
do {
80
crypto_lskcipher_decrypt(tfm, src, dst, bsize, NULL);
81
crypto_xor(dst, iv, bsize);
82
iv = src;
83
84
src += bsize;
85
dst += bsize;
86
} while ((nbytes -= bsize) >= bsize);
87
88
memcpy(oiv, iv, bsize);
89
90
out:
91
return nbytes;
92
}
93
94
static int crypto_cbc_decrypt_inplace(struct crypto_lskcipher *tfm,
95
u8 *src, unsigned nbytes, u8 *iv)
96
{
97
unsigned int bsize = crypto_lskcipher_blocksize(tfm);
98
u8 last_iv[MAX_CIPHER_BLOCKSIZE];
99
100
if (nbytes < bsize)
101
goto out;
102
103
/* Start of the last block. */
104
src += nbytes - (nbytes & (bsize - 1)) - bsize;
105
memcpy(last_iv, src, bsize);
106
107
for (;;) {
108
crypto_lskcipher_decrypt(tfm, src, src, bsize, NULL);
109
if ((nbytes -= bsize) < bsize)
110
break;
111
crypto_xor(src, src - bsize, bsize);
112
src -= bsize;
113
}
114
115
crypto_xor(src, iv, bsize);
116
memcpy(iv, last_iv, bsize);
117
118
out:
119
return nbytes;
120
}
121
122
static int crypto_cbc_decrypt(struct crypto_lskcipher *tfm, const u8 *src,
123
u8 *dst, unsigned len, u8 *iv, u32 flags)
124
{
125
struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm);
126
bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL;
127
struct crypto_lskcipher *cipher = *ctx;
128
int rem;
129
130
if (src == dst)
131
rem = crypto_cbc_decrypt_inplace(cipher, dst, len, iv);
132
else
133
rem = crypto_cbc_decrypt_segment(cipher, src, dst, len, iv);
134
135
return rem && final ? -EINVAL : rem;
136
}
137
138
static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
139
{
140
struct lskcipher_instance *inst;
141
int err;
142
143
inst = lskcipher_alloc_instance_simple(tmpl, tb);
144
if (IS_ERR(inst))
145
return PTR_ERR(inst);
146
147
err = -EINVAL;
148
if (!is_power_of_2(inst->alg.co.base.cra_blocksize))
149
goto out_free_inst;
150
151
if (inst->alg.co.statesize)
152
goto out_free_inst;
153
154
inst->alg.encrypt = crypto_cbc_encrypt;
155
inst->alg.decrypt = crypto_cbc_decrypt;
156
157
err = lskcipher_register_instance(tmpl, inst);
158
if (err) {
159
out_free_inst:
160
inst->free(inst);
161
}
162
163
return err;
164
}
165
166
static struct crypto_template crypto_cbc_tmpl = {
167
.name = "cbc",
168
.create = crypto_cbc_create,
169
.module = THIS_MODULE,
170
};
171
172
static int __init crypto_cbc_module_init(void)
173
{
174
return crypto_register_template(&crypto_cbc_tmpl);
175
}
176
177
static void __exit crypto_cbc_module_exit(void)
178
{
179
crypto_unregister_template(&crypto_cbc_tmpl);
180
}
181
182
module_init(crypto_cbc_module_init);
183
module_exit(crypto_cbc_module_exit);
184
185
MODULE_LICENSE("GPL");
186
MODULE_DESCRIPTION("CBC block cipher mode of operation");
187
MODULE_ALIAS_CRYPTO("cbc");
188
189