aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2016-11-22 07:08:42 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2016-11-28 08:23:21 -0500
commitcc868d82abca4a90a447bfd31b46b381ec144669 (patch)
treec793a9ad62175ba48ff5f5ce757fa5a6dce24987
parent79c65d179a40e145287e59b33dc782a7c4bf0986 (diff)
crypto: cbc - Export CBC implementation
This patch moves the core CBC implementation into a header file so that it can be reused by drivers implementing CBC. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/cbc.c129
-rw-r--r--include/crypto/cbc.h146
2 files changed, 148 insertions, 127 deletions
diff --git a/crypto/cbc.c b/crypto/cbc.c
index 6539b387668f..68f751a41a84 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * CBC: Cipher Block Chaining mode 2 * CBC: Cipher Block Chaining mode
3 * 3 *
4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 4 * Copyright (c) 2006-2016 Herbert Xu <herbert@gondor.apana.org.au>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 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 7 * under the terms of the GNU General Public License as published by the Free
@@ -10,6 +10,7 @@
10 * 10 *
11 */ 11 */
12 12
13#include <crypto/cbc.h>
13#include <crypto/internal/skcipher.h> 14#include <crypto/internal/skcipher.h>
14#include <linux/err.h> 15#include <linux/err.h>
15#include <linux/init.h> 16#include <linux/init.h>
@@ -38,71 +39,6 @@ static int crypto_cbc_setkey(struct crypto_skcipher *parent, const u8 *key,
38 return err; 39 return err;
39} 40}
40 41
41static inline int crypto_cbc_encrypt_segment(
42 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
43 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
44{
45 unsigned int bsize = crypto_skcipher_blocksize(tfm);
46 unsigned int nbytes = walk->nbytes;
47 u8 *src = walk->src.virt.addr;
48 u8 *dst = walk->dst.virt.addr;
49 u8 *iv = walk->iv;
50
51 do {
52 crypto_xor(iv, src, bsize);
53 fn(tfm, iv, dst);
54 memcpy(iv, dst, bsize);
55
56 src += bsize;
57 dst += bsize;
58 } while ((nbytes -= bsize) >= bsize);
59
60 return nbytes;
61}
62
63static inline int crypto_cbc_encrypt_inplace(
64 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
65 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
66{
67 unsigned int bsize = crypto_skcipher_blocksize(tfm);
68 unsigned int nbytes = walk->nbytes;
69 u8 *src = walk->src.virt.addr;
70 u8 *iv = walk->iv;
71
72 do {
73 crypto_xor(src, iv, bsize);
74 fn(tfm, src, src);
75 iv = src;
76
77 src += bsize;
78 } while ((nbytes -= bsize) >= bsize);
79
80 memcpy(walk->iv, iv, bsize);
81
82 return nbytes;
83}
84
85static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
86 void (*fn)(struct crypto_skcipher *,
87 const u8 *, u8 *))
88{
89 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
90 struct skcipher_walk walk;
91 int err;
92
93 err = skcipher_walk_virt(&walk, req, false);
94
95 while (walk.nbytes) {
96 if (walk.src.virt.addr == walk.dst.virt.addr)
97 err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
98 else
99 err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
100 err = skcipher_walk_done(&walk, err);
101 }
102
103 return err;
104}
105
106static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm, 42static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm,
107 const u8 *src, u8 *dst) 43 const u8 *src, u8 *dst)
108{ 44{
@@ -116,67 +52,6 @@ static int crypto_cbc_encrypt(struct skcipher_request *req)
116 return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one); 52 return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one);
117} 53}
118 54
119static inline int crypto_cbc_decrypt_segment(
120 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
121 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
122{
123 unsigned int bsize = crypto_skcipher_blocksize(tfm);
124 unsigned int nbytes = walk->nbytes;
125 u8 *src = walk->src.virt.addr;
126 u8 *dst = walk->dst.virt.addr;
127 u8 *iv = walk->iv;
128
129 do {
130 fn(tfm, src, dst);
131 crypto_xor(dst, iv, bsize);
132 iv = src;
133
134 src += bsize;
135 dst += bsize;
136 } while ((nbytes -= bsize) >= bsize);
137
138 memcpy(walk->iv, iv, bsize);
139
140 return nbytes;
141}
142
143static inline int crypto_cbc_decrypt_inplace(
144 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
145 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
146{
147 unsigned int bsize = crypto_skcipher_blocksize(tfm);
148 unsigned int nbytes = walk->nbytes;
149 u8 *src = walk->src.virt.addr;
150 u8 last_iv[bsize];
151
152 /* Start of the last block. */
153 src += nbytes - (nbytes & (bsize - 1)) - bsize;
154 memcpy(last_iv, src, bsize);
155
156 for (;;) {
157 fn(tfm, src, src);
158 if ((nbytes -= bsize) < bsize)
159 break;
160 crypto_xor(src, src - bsize, bsize);
161 src -= bsize;
162 }
163
164 crypto_xor(src, walk->iv, bsize);
165 memcpy(walk->iv, last_iv, bsize);
166
167 return nbytes;
168}
169
170static inline int crypto_cbc_decrypt_blocks(
171 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
172 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
173{
174 if (walk->src.virt.addr == walk->dst.virt.addr)
175 return crypto_cbc_decrypt_inplace(walk, tfm, fn);
176 else
177 return crypto_cbc_decrypt_segment(walk, tfm, fn);
178}
179
180static inline void crypto_cbc_decrypt_one(struct crypto_skcipher *tfm, 55static inline void crypto_cbc_decrypt_one(struct crypto_skcipher *tfm,
181 const u8 *src, u8 *dst) 56 const u8 *src, u8 *dst)
182{ 57{
diff --git a/include/crypto/cbc.h b/include/crypto/cbc.h
new file mode 100644
index 000000000000..f5b8bfc22e6d
--- /dev/null
+++ b/include/crypto/cbc.h
@@ -0,0 +1,146 @@
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 */