Loading...
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * CBC: Cipher Block Chaining mode
4 *
5 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
6 */
7
8#ifndef _CRYPTO_CBC_H
9#define _CRYPTO_CBC_H
10
11#include <crypto/internal/skcipher.h>
12#include <linux/string.h>
13#include <linux/types.h>
14
15static inline int crypto_cbc_encrypt_segment(
16 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
17 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
18{
19 unsigned int bsize = crypto_skcipher_blocksize(tfm);
20 unsigned int nbytes = walk->nbytes;
21 u8 *src = walk->src.virt.addr;
22 u8 *dst = walk->dst.virt.addr;
23 u8 *iv = walk->iv;
24
25 do {
26 crypto_xor(iv, src, bsize);
27 fn(tfm, iv, dst);
28 memcpy(iv, dst, bsize);
29
30 src += bsize;
31 dst += bsize;
32 } while ((nbytes -= bsize) >= bsize);
33
34 return nbytes;
35}
36
37static inline int crypto_cbc_encrypt_inplace(
38 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
39 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
40{
41 unsigned int bsize = crypto_skcipher_blocksize(tfm);
42 unsigned int nbytes = walk->nbytes;
43 u8 *src = walk->src.virt.addr;
44 u8 *iv = walk->iv;
45
46 do {
47 crypto_xor(src, iv, bsize);
48 fn(tfm, src, src);
49 iv = src;
50
51 src += bsize;
52 } while ((nbytes -= bsize) >= bsize);
53
54 memcpy(walk->iv, iv, bsize);
55
56 return nbytes;
57}
58
59static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
60 void (*fn)(struct crypto_skcipher *,
61 const u8 *, u8 *))
62{
63 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
64 struct skcipher_walk walk;
65 int err;
66
67 err = skcipher_walk_virt(&walk, req, false);
68
69 while (walk.nbytes) {
70 if (walk.src.virt.addr == walk.dst.virt.addr)
71 err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
72 else
73 err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
74 err = skcipher_walk_done(&walk, err);
75 }
76
77 return err;
78}
79
80static inline int crypto_cbc_decrypt_segment(
81 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
82 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
83{
84 unsigned int bsize = crypto_skcipher_blocksize(tfm);
85 unsigned int nbytes = walk->nbytes;
86 u8 *src = walk->src.virt.addr;
87 u8 *dst = walk->dst.virt.addr;
88 u8 *iv = walk->iv;
89
90 do {
91 fn(tfm, src, dst);
92 crypto_xor(dst, iv, bsize);
93 iv = src;
94
95 src += bsize;
96 dst += bsize;
97 } while ((nbytes -= bsize) >= bsize);
98
99 memcpy(walk->iv, iv, bsize);
100
101 return nbytes;
102}
103
104static inline int crypto_cbc_decrypt_inplace(
105 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
106 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
107{
108 unsigned int bsize = crypto_skcipher_blocksize(tfm);
109 unsigned int nbytes = walk->nbytes;
110 u8 *src = walk->src.virt.addr;
111 u8 last_iv[MAX_CIPHER_BLOCKSIZE];
112
113 /* Start of the last block. */
114 src += nbytes - (nbytes & (bsize - 1)) - bsize;
115 memcpy(last_iv, src, bsize);
116
117 for (;;) {
118 fn(tfm, src, src);
119 if ((nbytes -= bsize) < bsize)
120 break;
121 crypto_xor(src, src - bsize, bsize);
122 src -= bsize;
123 }
124
125 crypto_xor(src, walk->iv, bsize);
126 memcpy(walk->iv, last_iv, bsize);
127
128 return nbytes;
129}
130
131static inline int crypto_cbc_decrypt_blocks(
132 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
133 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
134{
135 if (walk->src.virt.addr == walk->dst.virt.addr)
136 return crypto_cbc_decrypt_inplace(walk, tfm, fn);
137 else
138 return crypto_cbc_decrypt_segment(walk, tfm, fn);
139}
140
141#endif /* _CRYPTO_CBC_H */
1/*
2 * CBC: Cipher Block Chaining mode
3 *
4 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 */
12
13#ifndef _CRYPTO_CBC_H
14#define _CRYPTO_CBC_H
15
16#include <crypto/internal/skcipher.h>
17#include <linux/string.h>
18#include <linux/types.h>
19
20static inline int crypto_cbc_encrypt_segment(
21 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
22 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
23{
24 unsigned int bsize = crypto_skcipher_blocksize(tfm);
25 unsigned int nbytes = walk->nbytes;
26 u8 *src = walk->src.virt.addr;
27 u8 *dst = walk->dst.virt.addr;
28 u8 *iv = walk->iv;
29
30 do {
31 crypto_xor(iv, src, bsize);
32 fn(tfm, iv, dst);
33 memcpy(iv, dst, bsize);
34
35 src += bsize;
36 dst += bsize;
37 } while ((nbytes -= bsize) >= bsize);
38
39 return nbytes;
40}
41
42static inline int crypto_cbc_encrypt_inplace(
43 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
44 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
45{
46 unsigned int bsize = crypto_skcipher_blocksize(tfm);
47 unsigned int nbytes = walk->nbytes;
48 u8 *src = walk->src.virt.addr;
49 u8 *iv = walk->iv;
50
51 do {
52 crypto_xor(src, iv, bsize);
53 fn(tfm, src, src);
54 iv = src;
55
56 src += bsize;
57 } while ((nbytes -= bsize) >= bsize);
58
59 memcpy(walk->iv, iv, bsize);
60
61 return nbytes;
62}
63
64static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
65 void (*fn)(struct crypto_skcipher *,
66 const u8 *, u8 *))
67{
68 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
69 struct skcipher_walk walk;
70 int err;
71
72 err = skcipher_walk_virt(&walk, req, false);
73
74 while (walk.nbytes) {
75 if (walk.src.virt.addr == walk.dst.virt.addr)
76 err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
77 else
78 err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
79 err = skcipher_walk_done(&walk, err);
80 }
81
82 return err;
83}
84
85static inline int crypto_cbc_decrypt_segment(
86 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
87 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
88{
89 unsigned int bsize = crypto_skcipher_blocksize(tfm);
90 unsigned int nbytes = walk->nbytes;
91 u8 *src = walk->src.virt.addr;
92 u8 *dst = walk->dst.virt.addr;
93 u8 *iv = walk->iv;
94
95 do {
96 fn(tfm, src, dst);
97 crypto_xor(dst, iv, bsize);
98 iv = src;
99
100 src += bsize;
101 dst += bsize;
102 } while ((nbytes -= bsize) >= bsize);
103
104 memcpy(walk->iv, iv, bsize);
105
106 return nbytes;
107}
108
109static inline int crypto_cbc_decrypt_inplace(
110 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
111 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
112{
113 unsigned int bsize = crypto_skcipher_blocksize(tfm);
114 unsigned int nbytes = walk->nbytes;
115 u8 *src = walk->src.virt.addr;
116 u8 last_iv[bsize];
117
118 /* Start of the last block. */
119 src += nbytes - (nbytes & (bsize - 1)) - bsize;
120 memcpy(last_iv, src, bsize);
121
122 for (;;) {
123 fn(tfm, src, src);
124 if ((nbytes -= bsize) < bsize)
125 break;
126 crypto_xor(src, src - bsize, bsize);
127 src -= bsize;
128 }
129
130 crypto_xor(src, walk->iv, bsize);
131 memcpy(walk->iv, last_iv, bsize);
132
133 return nbytes;
134}
135
136static inline int crypto_cbc_decrypt_blocks(
137 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
138 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
139{
140 if (walk->src.virt.addr == walk->dst.virt.addr)
141 return crypto_cbc_decrypt_inplace(walk, tfm, fn);
142 else
143 return crypto_cbc_decrypt_segment(walk, tfm, fn);
144}
145
146#endif /* _CRYPTO_CBC_H */