summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilad Ben-Yossef <gilad@benyossef.com>2018-09-20 09:18:39 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2018-09-28 00:46:26 -0400
commite497c51896b3babfb14a36e497fd36a15f56cfa4 (patch)
treef8f77c55ceea579c373c7b08c15ebfdbb714771e
parent95ba597367ddc26c1062c7ee9697c9aee53d04d0 (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/Kconfig12
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/ofb.c225
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
459config 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
459config CRYPTO_PCBC 471config 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
142obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o 142obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
143obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o 143obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
144obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o 144obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
145obj-$(CONFIG_CRYPTO_OFB) += ofb.o
145 146
146ecdh_generic-y := ecc.o 147ecdh_generic-y := ecc.o
147ecdh_generic-y += ecdh.o 148ecdh_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
22struct crypto_ofb_ctx {
23 struct crypto_cipher *child;
24 int cnt;
25};
26
27
28static 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
44static 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
70static 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 */
93static int crypto_ofb_decrypt(struct skcipher_request *req)
94{
95 return crypto_ofb_encrypt(req);
96}
97
98static 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
113static 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
120static void crypto_ofb_free(struct skcipher_instance *inst)
121{
122 crypto_drop_skcipher(skcipher_instance_ctx(inst));
123 kfree(inst);
124}
125
126static 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
194out:
195 return err;
196
197err_drop_spawn:
198 crypto_drop_spawn(spawn);
199err_free_inst:
200 kfree(inst);
201 goto out;
202}
203
204static struct crypto_template crypto_ofb_tmpl = {
205 .name = "ofb",
206 .create = crypto_ofb_create,
207 .module = THIS_MODULE,
208};
209
210static int __init crypto_ofb_module_init(void)
211{
212 return crypto_register_template(&crypto_ofb_tmpl);
213}
214
215static void __exit crypto_ofb_module_exit(void)
216{
217 crypto_unregister_template(&crypto_ofb_tmpl);
218}
219
220module_init(crypto_ofb_module_init);
221module_exit(crypto_ofb_module_exit);
222
223MODULE_LICENSE("GPL");
224MODULE_DESCRIPTION("OFB block cipher algorithm");
225MODULE_ALIAS_CRYPTO("ofb");