Blame view

crypto/cbc.c 5.15 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
2
3
4
  /*
   * CBC: Cipher Block Chaining mode
   *
cc868d82a   Herbert Xu   crypto: cbc - Exp...
5
   * Copyright (c) 2006-2016 Herbert Xu <herbert@gondor.apana.org.au>
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
6
   */
e6c2e65c7   Marcelo Cerri   crypto: cbc - Pro...
7
  #include <crypto/algapi.h>
79c65d179   Herbert Xu   crypto: cbc - Con...
8
  #include <crypto/internal/skcipher.h>
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
9
10
11
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
50b6544e1   Herbert Xu   [CRYPTO] cbc: Req...
12
  #include <linux/log2.h>
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
13
  #include <linux/module.h>
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
14

5f254dd44   Herbert Xu   crypto: cbc - Rem...
15
16
  static int crypto_cbc_encrypt_segment(struct skcipher_walk *walk,
  				      struct crypto_skcipher *skcipher)
79c65d179   Herbert Xu   crypto: cbc - Con...
17
  {
5f254dd44   Herbert Xu   crypto: cbc - Rem...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	u8 *dst = walk->dst.virt.addr;
  	struct crypto_cipher *cipher;
  	struct crypto_tfm *tfm;
  	u8 *iv = walk->iv;
  
  	cipher = skcipher_cipher_simple(skcipher);
  	tfm = crypto_cipher_tfm(cipher);
  	fn = crypto_cipher_alg(cipher)->cia_encrypt;
  
  	do {
  		crypto_xor(iv, src, bsize);
  		fn(tfm, dst, iv);
  		memcpy(iv, dst, bsize);
  
  		src += bsize;
  		dst += bsize;
  	} while ((nbytes -= bsize) >= bsize);
  
  	return nbytes;
  }
  
  static int crypto_cbc_encrypt_inplace(struct skcipher_walk *walk,
  				      struct crypto_skcipher *skcipher)
  {
  	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	struct crypto_cipher *cipher;
  	struct crypto_tfm *tfm;
  	u8 *iv = walk->iv;
  
  	cipher = skcipher_cipher_simple(skcipher);
  	tfm = crypto_cipher_tfm(cipher);
  	fn = crypto_cipher_alg(cipher)->cia_encrypt;
  
  	do {
  		crypto_xor(src, iv, bsize);
  		fn(tfm, src, src);
  		iv = src;
  
  		src += bsize;
  	} while ((nbytes -= bsize) >= bsize);
  
  	memcpy(walk->iv, iv, bsize);
  
  	return nbytes;
79c65d179   Herbert Xu   crypto: cbc - Con...
69
70
71
  }
  
  static int crypto_cbc_encrypt(struct skcipher_request *req)
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
72
  {
5f254dd44   Herbert Xu   crypto: cbc - Rem...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
  	struct skcipher_walk walk;
  	int err;
  
  	err = skcipher_walk_virt(&walk, req, false);
  
  	while (walk.nbytes) {
  		if (walk.src.virt.addr == walk.dst.virt.addr)
  			err = crypto_cbc_encrypt_inplace(&walk, skcipher);
  		else
  			err = crypto_cbc_encrypt_segment(&walk, skcipher);
  		err = skcipher_walk_done(&walk, err);
  	}
  
  	return err;
  }
  
  static int crypto_cbc_decrypt_segment(struct skcipher_walk *walk,
  				      struct crypto_skcipher *skcipher)
  {
  	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	u8 *dst = walk->dst.virt.addr;
  	struct crypto_cipher *cipher;
  	struct crypto_tfm *tfm;
  	u8 *iv = walk->iv;
  
  	cipher = skcipher_cipher_simple(skcipher);
  	tfm = crypto_cipher_tfm(cipher);
  	fn = crypto_cipher_alg(cipher)->cia_decrypt;
  
  	do {
  		fn(tfm, dst, src);
  		crypto_xor(dst, iv, bsize);
  		iv = src;
  
  		src += bsize;
  		dst += bsize;
  	} while ((nbytes -= bsize) >= bsize);
  
  	memcpy(walk->iv, iv, bsize);
  
  	return nbytes;
79c65d179   Herbert Xu   crypto: cbc - Con...
118
  }
5f254dd44   Herbert Xu   crypto: cbc - Rem...
119
120
  static int crypto_cbc_decrypt_inplace(struct skcipher_walk *walk,
  				      struct crypto_skcipher *skcipher)
79c65d179   Herbert Xu   crypto: cbc - Con...
121
  {
5f254dd44   Herbert Xu   crypto: cbc - Rem...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
  	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	u8 last_iv[MAX_CIPHER_BLOCKSIZE];
  	struct crypto_cipher *cipher;
  	struct crypto_tfm *tfm;
  
  	cipher = skcipher_cipher_simple(skcipher);
  	tfm = crypto_cipher_tfm(cipher);
  	fn = crypto_cipher_alg(cipher)->cia_decrypt;
  
  	/* Start of the last block. */
  	src += nbytes - (nbytes & (bsize - 1)) - bsize;
  	memcpy(last_iv, src, bsize);
  
  	for (;;) {
  		fn(tfm, src, src);
  		if ((nbytes -= bsize) < bsize)
  			break;
  		crypto_xor(src, src - bsize, bsize);
  		src -= bsize;
  	}
  
  	crypto_xor(src, walk->iv, bsize);
  	memcpy(walk->iv, last_iv, bsize);
  
  	return nbytes;
79c65d179   Herbert Xu   crypto: cbc - Con...
150
151
152
153
  }
  
  static int crypto_cbc_decrypt(struct skcipher_request *req)
  {
5f254dd44   Herbert Xu   crypto: cbc - Rem...
154
  	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
79c65d179   Herbert Xu   crypto: cbc - Con...
155
  	struct skcipher_walk walk;
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
156
  	int err;
79c65d179   Herbert Xu   crypto: cbc - Con...
157
  	err = skcipher_walk_virt(&walk, req, false);
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
158

79c65d179   Herbert Xu   crypto: cbc - Con...
159
  	while (walk.nbytes) {
5f254dd44   Herbert Xu   crypto: cbc - Rem...
160
161
162
163
  		if (walk.src.virt.addr == walk.dst.virt.addr)
  			err = crypto_cbc_decrypt_inplace(&walk, skcipher);
  		else
  			err = crypto_cbc_decrypt_segment(&walk, skcipher);
79c65d179   Herbert Xu   crypto: cbc - Con...
164
  		err = skcipher_walk_done(&walk, err);
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
165
166
167
168
  	}
  
  	return err;
  }
79c65d179   Herbert Xu   crypto: cbc - Con...
169
170
171
  static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
  {
  	struct skcipher_instance *inst;
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
172
  	struct crypto_alg *alg;
ebc610e5b   Herbert Xu   [CRYPTO] template...
173
  	int err;
b3c16bfc6   Herbert Xu   crypto: skcipher ...
174
  	inst = skcipher_alloc_instance_simple(tmpl, tb);
a5a84a9db   Eric Biggers   crypto: cbc - con...
175
176
  	if (IS_ERR(inst))
  		return PTR_ERR(inst);
50b6544e1   Herbert Xu   [CRYPTO] cbc: Req...
177

b3c16bfc6   Herbert Xu   crypto: skcipher ...
178
  	alg = skcipher_ialg_simple(inst);
79c65d179   Herbert Xu   crypto: cbc - Con...
179
180
  	err = -EINVAL;
  	if (!is_power_of_2(alg->cra_blocksize))
a5a84a9db   Eric Biggers   crypto: cbc - con...
181
  		goto out_free_inst;
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
182

79c65d179   Herbert Xu   crypto: cbc - Con...
183
184
  	inst->alg.encrypt = crypto_cbc_encrypt;
  	inst->alg.decrypt = crypto_cbc_decrypt;
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
185

79c65d179   Herbert Xu   crypto: cbc - Con...
186
  	err = skcipher_register_instance(tmpl, inst);
b3c16bfc6   Herbert Xu   crypto: skcipher ...
187
  	if (err) {
a5a84a9db   Eric Biggers   crypto: cbc - con...
188
  out_free_inst:
b3c16bfc6   Herbert Xu   crypto: skcipher ...
189
190
  		inst->free(inst);
  	}
a5a84a9db   Eric Biggers   crypto: cbc - con...
191
  	return err;
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
192
193
194
195
  }
  
  static struct crypto_template crypto_cbc_tmpl = {
  	.name = "cbc",
79c65d179   Herbert Xu   crypto: cbc - Con...
196
  	.create = crypto_cbc_create,
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
197
198
199
200
201
202
203
204
205
206
207
208
  	.module = THIS_MODULE,
  };
  
  static int __init crypto_cbc_module_init(void)
  {
  	return crypto_register_template(&crypto_cbc_tmpl);
  }
  
  static void __exit crypto_cbc_module_exit(void)
  {
  	crypto_unregister_template(&crypto_cbc_tmpl);
  }
c4741b230   Eric Biggers   crypto: run initc...
209
  subsys_initcall(crypto_cbc_module_init);
db131ef90   Herbert Xu   [CRYPTO] cipher: ...
210
211
212
  module_exit(crypto_cbc_module_exit);
  
  MODULE_LICENSE("GPL");
a5a84a9db   Eric Biggers   crypto: cbc - con...
213
  MODULE_DESCRIPTION("CBC block cipher mode of operation");
4943ba16b   Kees Cook   crypto: include c...
214
  MODULE_ALIAS_CRYPTO("cbc");