diff options
author | Gilad Ben-Yossef <gilad@benyossef.com> | 2018-09-20 09:18:39 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-09-28 00:46:26 -0400 |
commit | e497c51896b3babfb14a36e497fd36a15f56cfa4 (patch) | |
tree | f8f77c55ceea579c373c7b08c15ebfdbb714771e | |
parent | 95ba597367ddc26c1062c7ee9697c9aee53d04d0 (diff) |
crypto: ofb - add output feedback mode
Add a generic version of output feedback mode. We already have support of
several hardware based transformations of this mode and the needed test
vectors but we somehow missed adding a generic software one. Fix this now.
Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/Kconfig | 12 | ||||
-rw-r--r-- | crypto/Makefile | 1 | ||||
-rw-r--r-- | crypto/ofb.c | 225 |
3 files changed, 238 insertions, 0 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 4ef95b0b25a3..63ef279322d2 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -456,6 +456,18 @@ config CRYPTO_LRW | |||
456 | The first 128, 192 or 256 bits in the key are used for AES and the | 456 | The first 128, 192 or 256 bits in the key are used for AES and the |
457 | rest is used to tie each cipher block to its logical position. | 457 | rest is used to tie each cipher block to its logical position. |
458 | 458 | ||
459 | config CRYPTO_OFB | ||
460 | tristate "OFB support" | ||
461 | select CRYPTO_BLKCIPHER | ||
462 | select CRYPTO_MANAGER | ||
463 | help | ||
464 | OFB: the Output Feedback mode makes a block cipher into a synchronous | ||
465 | stream cipher. It generates keystream blocks, which are then XORed | ||
466 | with the plaintext blocks to get the ciphertext. Flipping a bit in the | ||
467 | ciphertext produces a flipped bit in the plaintext at the same | ||
468 | location. This property allows many error correcting codes to function | ||
469 | normally even when applied before encryption. | ||
470 | |||
459 | config CRYPTO_PCBC | 471 | config CRYPTO_PCBC |
460 | tristate "PCBC support" | 472 | tristate "PCBC support" |
461 | select CRYPTO_BLKCIPHER | 473 | select CRYPTO_BLKCIPHER |
diff --git a/crypto/Makefile b/crypto/Makefile index ff5c2bbda04a..5c207c76abf7 100644 --- a/crypto/Makefile +++ b/crypto/Makefile | |||
@@ -142,6 +142,7 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o | |||
142 | obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o | 142 | obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o |
143 | obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o | 143 | obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o |
144 | obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o | 144 | obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o |
145 | obj-$(CONFIG_CRYPTO_OFB) += ofb.o | ||
145 | 146 | ||
146 | ecdh_generic-y := ecc.o | 147 | ecdh_generic-y := ecc.o |
147 | ecdh_generic-y += ecdh.o | 148 | ecdh_generic-y += ecdh.o |
diff --git a/crypto/ofb.c b/crypto/ofb.c new file mode 100644 index 000000000000..886631708c5e --- /dev/null +++ b/crypto/ofb.c | |||
@@ -0,0 +1,225 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | /* | ||
4 | * OFB: Output FeedBack mode | ||
5 | * | ||
6 | * Copyright (C) 2018 ARM Limited or its affiliates. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Based loosely on public domain code gleaned from libtomcrypt | ||
10 | * (https://github.com/libtom/libtomcrypt). | ||
11 | */ | ||
12 | |||
13 | #include <crypto/algapi.h> | ||
14 | #include <crypto/internal/skcipher.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | struct crypto_ofb_ctx { | ||
23 | struct crypto_cipher *child; | ||
24 | int cnt; | ||
25 | }; | ||
26 | |||
27 | |||
28 | static int crypto_ofb_setkey(struct crypto_skcipher *parent, const u8 *key, | ||
29 | unsigned int keylen) | ||
30 | { | ||
31 | struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(parent); | ||
32 | struct crypto_cipher *child = ctx->child; | ||
33 | int err; | ||
34 | |||
35 | crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); | ||
36 | crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) & | ||
37 | CRYPTO_TFM_REQ_MASK); | ||
38 | err = crypto_cipher_setkey(child, key, keylen); | ||
39 | crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) & | ||
40 | CRYPTO_TFM_RES_MASK); | ||
41 | return err; | ||
42 | } | ||
43 | |||
44 | static int crypto_ofb_encrypt_segment(struct crypto_ofb_ctx *ctx, | ||
45 | struct skcipher_walk *walk, | ||
46 | struct crypto_cipher *tfm) | ||
47 | { | ||
48 | int bsize = crypto_cipher_blocksize(tfm); | ||
49 | int nbytes = walk->nbytes; | ||
50 | |||
51 | u8 *src = walk->src.virt.addr; | ||
52 | u8 *dst = walk->dst.virt.addr; | ||
53 | u8 *iv = walk->iv; | ||
54 | |||
55 | do { | ||
56 | if (ctx->cnt == bsize) { | ||
57 | if (nbytes < bsize) | ||
58 | break; | ||
59 | crypto_cipher_encrypt_one(tfm, iv, iv); | ||
60 | ctx->cnt = 0; | ||
61 | } | ||
62 | *dst = *src ^ iv[ctx->cnt]; | ||
63 | src++; | ||
64 | dst++; | ||
65 | ctx->cnt++; | ||
66 | } while (--nbytes); | ||
67 | return nbytes; | ||
68 | } | ||
69 | |||
70 | static int crypto_ofb_encrypt(struct skcipher_request *req) | ||
71 | { | ||
72 | struct skcipher_walk walk; | ||
73 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | ||
74 | unsigned int bsize; | ||
75 | struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
76 | struct crypto_cipher *child = ctx->child; | ||
77 | int ret = 0; | ||
78 | |||
79 | bsize = crypto_cipher_blocksize(child); | ||
80 | ctx->cnt = bsize; | ||
81 | |||
82 | ret = skcipher_walk_virt(&walk, req, false); | ||
83 | |||
84 | while (walk.nbytes) { | ||
85 | ret = crypto_ofb_encrypt_segment(ctx, &walk, child); | ||
86 | ret = skcipher_walk_done(&walk, ret); | ||
87 | } | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | /* OFB encrypt and decrypt are identical */ | ||
93 | static int crypto_ofb_decrypt(struct skcipher_request *req) | ||
94 | { | ||
95 | return crypto_ofb_encrypt(req); | ||
96 | } | ||
97 | |||
98 | static int crypto_ofb_init_tfm(struct crypto_skcipher *tfm) | ||
99 | { | ||
100 | struct skcipher_instance *inst = skcipher_alg_instance(tfm); | ||
101 | struct crypto_spawn *spawn = skcipher_instance_ctx(inst); | ||
102 | struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
103 | struct crypto_cipher *cipher; | ||
104 | |||
105 | cipher = crypto_spawn_cipher(spawn); | ||
106 | if (IS_ERR(cipher)) | ||
107 | return PTR_ERR(cipher); | ||
108 | |||
109 | ctx->child = cipher; | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static void crypto_ofb_exit_tfm(struct crypto_skcipher *tfm) | ||
114 | { | ||
115 | struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
116 | |||
117 | crypto_free_cipher(ctx->child); | ||
118 | } | ||
119 | |||
120 | static void crypto_ofb_free(struct skcipher_instance *inst) | ||
121 | { | ||
122 | crypto_drop_skcipher(skcipher_instance_ctx(inst)); | ||
123 | kfree(inst); | ||
124 | } | ||
125 | |||
126 | static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb) | ||
127 | { | ||
128 | struct skcipher_instance *inst; | ||
129 | struct crypto_attr_type *algt; | ||
130 | struct crypto_spawn *spawn; | ||
131 | struct crypto_alg *alg; | ||
132 | u32 mask; | ||
133 | int err; | ||
134 | |||
135 | err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER); | ||
136 | if (err) | ||
137 | return err; | ||
138 | |||
139 | inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); | ||
140 | if (!inst) | ||
141 | return -ENOMEM; | ||
142 | |||
143 | algt = crypto_get_attr_type(tb); | ||
144 | err = PTR_ERR(algt); | ||
145 | if (IS_ERR(algt)) | ||
146 | goto err_free_inst; | ||
147 | |||
148 | mask = CRYPTO_ALG_TYPE_MASK | | ||
149 | crypto_requires_off(algt->type, algt->mask, | ||
150 | CRYPTO_ALG_NEED_FALLBACK); | ||
151 | |||
152 | alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask); | ||
153 | err = PTR_ERR(alg); | ||
154 | if (IS_ERR(alg)) | ||
155 | goto err_free_inst; | ||
156 | |||
157 | spawn = skcipher_instance_ctx(inst); | ||
158 | err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst), | ||
159 | CRYPTO_ALG_TYPE_MASK); | ||
160 | crypto_mod_put(alg); | ||
161 | if (err) | ||
162 | goto err_free_inst; | ||
163 | |||
164 | err = crypto_inst_setname(skcipher_crypto_instance(inst), "ofb", alg); | ||
165 | if (err) | ||
166 | goto err_drop_spawn; | ||
167 | |||
168 | inst->alg.base.cra_priority = alg->cra_priority; | ||
169 | inst->alg.base.cra_blocksize = alg->cra_blocksize; | ||
170 | inst->alg.base.cra_alignmask = alg->cra_alignmask; | ||
171 | |||
172 | /* We access the data as u32s when xoring. */ | ||
173 | inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; | ||
174 | |||
175 | inst->alg.ivsize = alg->cra_blocksize; | ||
176 | inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize; | ||
177 | inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize; | ||
178 | |||
179 | inst->alg.base.cra_ctxsize = sizeof(struct crypto_ofb_ctx); | ||
180 | |||
181 | inst->alg.init = crypto_ofb_init_tfm; | ||
182 | inst->alg.exit = crypto_ofb_exit_tfm; | ||
183 | |||
184 | inst->alg.setkey = crypto_ofb_setkey; | ||
185 | inst->alg.encrypt = crypto_ofb_encrypt; | ||
186 | inst->alg.decrypt = crypto_ofb_decrypt; | ||
187 | |||
188 | inst->free = crypto_ofb_free; | ||
189 | |||
190 | err = skcipher_register_instance(tmpl, inst); | ||
191 | if (err) | ||
192 | goto err_drop_spawn; | ||
193 | |||
194 | out: | ||
195 | return err; | ||
196 | |||
197 | err_drop_spawn: | ||
198 | crypto_drop_spawn(spawn); | ||
199 | err_free_inst: | ||
200 | kfree(inst); | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | static struct crypto_template crypto_ofb_tmpl = { | ||
205 | .name = "ofb", | ||
206 | .create = crypto_ofb_create, | ||
207 | .module = THIS_MODULE, | ||
208 | }; | ||
209 | |||
210 | static int __init crypto_ofb_module_init(void) | ||
211 | { | ||
212 | return crypto_register_template(&crypto_ofb_tmpl); | ||
213 | } | ||
214 | |||
215 | static void __exit crypto_ofb_module_exit(void) | ||
216 | { | ||
217 | crypto_unregister_template(&crypto_ofb_tmpl); | ||
218 | } | ||
219 | |||
220 | module_init(crypto_ofb_module_init); | ||
221 | module_exit(crypto_ofb_module_exit); | ||
222 | |||
223 | MODULE_LICENSE("GPL"); | ||
224 | MODULE_DESCRIPTION("OFB block cipher algorithm"); | ||
225 | MODULE_ALIAS_CRYPTO("ofb"); | ||