~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/crypto/cbc.c

Version: ~ [ linux-5.16 ] ~ [ linux-5.15.13 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.90 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.170 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.224 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.261 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.296 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.298 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * CBC: Cipher Block Chaining mode
  4  *
  5  * Copyright (c) 2006-2016 Herbert Xu <herbert@gondor.apana.org.au>
  6  */
  7 
  8 #include <crypto/algapi.h>
  9 #include <crypto/internal/cipher.h>
 10 #include <crypto/internal/skcipher.h>
 11 #include <linux/err.h>
 12 #include <linux/init.h>
 13 #include <linux/kernel.h>
 14 #include <linux/log2.h>
 15 #include <linux/module.h>
 16 
 17 static int crypto_cbc_encrypt_segment(struct skcipher_walk *walk,
 18                                       struct crypto_skcipher *skcipher)
 19 {
 20         unsigned int bsize = crypto_skcipher_blocksize(skcipher);
 21         void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
 22         unsigned int nbytes = walk->nbytes;
 23         u8 *src = walk->src.virt.addr;
 24         u8 *dst = walk->dst.virt.addr;
 25         struct crypto_cipher *cipher;
 26         struct crypto_tfm *tfm;
 27         u8 *iv = walk->iv;
 28 
 29         cipher = skcipher_cipher_simple(skcipher);
 30         tfm = crypto_cipher_tfm(cipher);
 31         fn = crypto_cipher_alg(cipher)->cia_encrypt;
 32 
 33         do {
 34                 crypto_xor(iv, src, bsize);
 35                 fn(tfm, dst, iv);
 36                 memcpy(iv, dst, bsize);
 37 
 38                 src += bsize;
 39                 dst += bsize;
 40         } while ((nbytes -= bsize) >= bsize);
 41 
 42         return nbytes;
 43 }
 44 
 45 static int crypto_cbc_encrypt_inplace(struct skcipher_walk *walk,
 46                                       struct crypto_skcipher *skcipher)
 47 {
 48         unsigned int bsize = crypto_skcipher_blocksize(skcipher);
 49         void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
 50         unsigned int nbytes = walk->nbytes;
 51         u8 *src = walk->src.virt.addr;
 52         struct crypto_cipher *cipher;
 53         struct crypto_tfm *tfm;
 54         u8 *iv = walk->iv;
 55 
 56         cipher = skcipher_cipher_simple(skcipher);
 57         tfm = crypto_cipher_tfm(cipher);
 58         fn = crypto_cipher_alg(cipher)->cia_encrypt;
 59 
 60         do {
 61                 crypto_xor(src, iv, bsize);
 62                 fn(tfm, src, src);
 63                 iv = src;
 64 
 65                 src += bsize;
 66         } while ((nbytes -= bsize) >= bsize);
 67 
 68         memcpy(walk->iv, iv, bsize);
 69 
 70         return nbytes;
 71 }
 72 
 73 static int crypto_cbc_encrypt(struct skcipher_request *req)
 74 {
 75         struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
 76         struct skcipher_walk walk;
 77         int err;
 78 
 79         err = skcipher_walk_virt(&walk, req, false);
 80 
 81         while (walk.nbytes) {
 82                 if (walk.src.virt.addr == walk.dst.virt.addr)
 83                         err = crypto_cbc_encrypt_inplace(&walk, skcipher);
 84                 else
 85                         err = crypto_cbc_encrypt_segment(&walk, skcipher);
 86                 err = skcipher_walk_done(&walk, err);
 87         }
 88 
 89         return err;
 90 }
 91 
 92 static int crypto_cbc_decrypt_segment(struct skcipher_walk *walk,
 93                                       struct crypto_skcipher *skcipher)
 94 {
 95         unsigned int bsize = crypto_skcipher_blocksize(skcipher);
 96         void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
 97         unsigned int nbytes = walk->nbytes;
 98         u8 *src = walk->src.virt.addr;
 99         u8 *dst = walk->dst.virt.addr;
100         struct crypto_cipher *cipher;
101         struct crypto_tfm *tfm;
102         u8 *iv = walk->iv;
103 
104         cipher = skcipher_cipher_simple(skcipher);
105         tfm = crypto_cipher_tfm(cipher);
106         fn = crypto_cipher_alg(cipher)->cia_decrypt;
107 
108         do {
109                 fn(tfm, dst, src);
110                 crypto_xor(dst, iv, bsize);
111                 iv = src;
112 
113                 src += bsize;
114                 dst += bsize;
115         } while ((nbytes -= bsize) >= bsize);
116 
117         memcpy(walk->iv, iv, bsize);
118 
119         return nbytes;
120 }
121 
122 static int crypto_cbc_decrypt_inplace(struct skcipher_walk *walk,
123                                       struct crypto_skcipher *skcipher)
124 {
125         unsigned int bsize = crypto_skcipher_blocksize(skcipher);
126         void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
127         unsigned int nbytes = walk->nbytes;
128         u8 *src = walk->src.virt.addr;
129         u8 last_iv[MAX_CIPHER_BLOCKSIZE];
130         struct crypto_cipher *cipher;
131         struct crypto_tfm *tfm;
132 
133         cipher = skcipher_cipher_simple(skcipher);
134         tfm = crypto_cipher_tfm(cipher);
135         fn = crypto_cipher_alg(cipher)->cia_decrypt;
136 
137         /* Start of the last block. */
138         src += nbytes - (nbytes & (bsize - 1)) - bsize;
139         memcpy(last_iv, src, bsize);
140 
141         for (;;) {
142                 fn(tfm, src, src);
143                 if ((nbytes -= bsize) < bsize)
144                         break;
145                 crypto_xor(src, src - bsize, bsize);
146                 src -= bsize;
147         }
148 
149         crypto_xor(src, walk->iv, bsize);
150         memcpy(walk->iv, last_iv, bsize);
151 
152         return nbytes;
153 }
154 
155 static int crypto_cbc_decrypt(struct skcipher_request *req)
156 {
157         struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
158         struct skcipher_walk walk;
159         int err;
160 
161         err = skcipher_walk_virt(&walk, req, false);
162 
163         while (walk.nbytes) {
164                 if (walk.src.virt.addr == walk.dst.virt.addr)
165                         err = crypto_cbc_decrypt_inplace(&walk, skcipher);
166                 else
167                         err = crypto_cbc_decrypt_segment(&walk, skcipher);
168                 err = skcipher_walk_done(&walk, err);
169         }
170 
171         return err;
172 }
173 
174 static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
175 {
176         struct skcipher_instance *inst;
177         struct crypto_alg *alg;
178         int err;
179 
180         inst = skcipher_alloc_instance_simple(tmpl, tb);
181         if (IS_ERR(inst))
182                 return PTR_ERR(inst);
183 
184         alg = skcipher_ialg_simple(inst);
185 
186         err = -EINVAL;
187         if (!is_power_of_2(alg->cra_blocksize))
188                 goto out_free_inst;
189 
190         inst->alg.encrypt = crypto_cbc_encrypt;
191         inst->alg.decrypt = crypto_cbc_decrypt;
192 
193         err = skcipher_register_instance(tmpl, inst);
194         if (err) {
195 out_free_inst:
196                 inst->free(inst);
197         }
198 
199         return err;
200 }
201 
202 static struct crypto_template crypto_cbc_tmpl = {
203         .name = "cbc",
204         .create = crypto_cbc_create,
205         .module = THIS_MODULE,
206 };
207 
208 static int __init crypto_cbc_module_init(void)
209 {
210         return crypto_register_template(&crypto_cbc_tmpl);
211 }
212 
213 static void __exit crypto_cbc_module_exit(void)
214 {
215         crypto_unregister_template(&crypto_cbc_tmpl);
216 }
217 
218 subsys_initcall(crypto_cbc_module_init);
219 module_exit(crypto_cbc_module_exit);
220 
221 MODULE_LICENSE("GPL");
222 MODULE_DESCRIPTION("CBC block cipher mode of operation");
223 MODULE_ALIAS_CRYPTO("cbc");
224 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp