OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [crypto/] [pcbc.c] - Blame information for rev 82

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * PCBC: Propagating Cipher Block Chaining mode
3
 *
4
 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
5
 * Written by David Howells (dhowells@redhat.com)
6
 *
7
 * Derived from cbc.c
8
 * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
9
 *
10
 * This program is free software; you can redistribute it and/or modify it
11
 * under the terms of the GNU General Public License as published by the Free
12
 * Software Foundation; either version 2 of the License, or (at your option)
13
 * any later version.
14
 *
15
 */
16
 
17
#include <crypto/algapi.h>
18
#include <linux/err.h>
19
#include <linux/init.h>
20
#include <linux/kernel.h>
21
#include <linux/module.h>
22
#include <linux/scatterlist.h>
23
#include <linux/slab.h>
24
 
25
struct crypto_pcbc_ctx {
26
        struct crypto_cipher *child;
27
        void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
28
};
29
 
30
static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
31
                              unsigned int keylen)
32
{
33
        struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent);
34
        struct crypto_cipher *child = ctx->child;
35
        int err;
36
 
37
        crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
38
        crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
39
                                CRYPTO_TFM_REQ_MASK);
40
        err = crypto_cipher_setkey(child, key, keylen);
41
        crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
42
                             CRYPTO_TFM_RES_MASK);
43
        return err;
44
}
45
 
46
static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
47
                                       struct blkcipher_walk *walk,
48
                                       struct crypto_cipher *tfm,
49
                                       void (*xor)(u8 *, const u8 *,
50
                                                   unsigned int))
51
{
52
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
53
                crypto_cipher_alg(tfm)->cia_encrypt;
54
        int bsize = crypto_cipher_blocksize(tfm);
55
        unsigned int nbytes = walk->nbytes;
56
        u8 *src = walk->src.virt.addr;
57
        u8 *dst = walk->dst.virt.addr;
58
        u8 *iv = walk->iv;
59
 
60
        do {
61
                xor(iv, src, bsize);
62
                fn(crypto_cipher_tfm(tfm), dst, iv);
63
                memcpy(iv, dst, bsize);
64
                xor(iv, src, bsize);
65
 
66
                src += bsize;
67
                dst += bsize;
68
        } while ((nbytes -= bsize) >= bsize);
69
 
70
        return nbytes;
71
}
72
 
73
static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
74
                                       struct blkcipher_walk *walk,
75
                                       struct crypto_cipher *tfm,
76
                                       void (*xor)(u8 *, const u8 *,
77
                                                   unsigned int))
78
{
79
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
80
                crypto_cipher_alg(tfm)->cia_encrypt;
81
        int bsize = crypto_cipher_blocksize(tfm);
82
        unsigned int nbytes = walk->nbytes;
83
        u8 *src = walk->src.virt.addr;
84
        u8 *iv = walk->iv;
85
        u8 tmpbuf[bsize];
86
 
87
        do {
88
                memcpy(tmpbuf, src, bsize);
89
                xor(iv, tmpbuf, bsize);
90
                fn(crypto_cipher_tfm(tfm), src, iv);
91
                memcpy(iv, src, bsize);
92
                xor(iv, tmpbuf, bsize);
93
 
94
                src += bsize;
95
        } while ((nbytes -= bsize) >= bsize);
96
 
97
        memcpy(walk->iv, iv, bsize);
98
 
99
        return nbytes;
100
}
101
 
102
static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
103
                               struct scatterlist *dst, struct scatterlist *src,
104
                               unsigned int nbytes)
105
{
106
        struct blkcipher_walk walk;
107
        struct crypto_blkcipher *tfm = desc->tfm;
108
        struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
109
        struct crypto_cipher *child = ctx->child;
110
        void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
111
        int err;
112
 
113
        blkcipher_walk_init(&walk, dst, src, nbytes);
114
        err = blkcipher_walk_virt(desc, &walk);
115
 
116
        while ((nbytes = walk.nbytes)) {
117
                if (walk.src.virt.addr == walk.dst.virt.addr)
118
                        nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child,
119
                                                             xor);
120
                else
121
                        nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child,
122
                                                             xor);
123
                err = blkcipher_walk_done(desc, &walk, nbytes);
124
        }
125
 
126
        return err;
127
}
128
 
129
static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
130
                                       struct blkcipher_walk *walk,
131
                                       struct crypto_cipher *tfm,
132
                                       void (*xor)(u8 *, const u8 *,
133
                                                   unsigned int))
134
{
135
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
136
                crypto_cipher_alg(tfm)->cia_decrypt;
137
        int bsize = crypto_cipher_blocksize(tfm);
138
        unsigned int nbytes = walk->nbytes;
139
        u8 *src = walk->src.virt.addr;
140
        u8 *dst = walk->dst.virt.addr;
141
        u8 *iv = walk->iv;
142
 
143
        do {
144
                fn(crypto_cipher_tfm(tfm), dst, src);
145
                xor(dst, iv, bsize);
146
                memcpy(iv, src, bsize);
147
                xor(iv, dst, bsize);
148
 
149
                src += bsize;
150
                dst += bsize;
151
        } while ((nbytes -= bsize) >= bsize);
152
 
153
        memcpy(walk->iv, iv, bsize);
154
 
155
        return nbytes;
156
}
157
 
158
static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
159
                                       struct blkcipher_walk *walk,
160
                                       struct crypto_cipher *tfm,
161
                                       void (*xor)(u8 *, const u8 *,
162
                                                   unsigned int))
163
{
164
        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
165
                crypto_cipher_alg(tfm)->cia_decrypt;
166
        int bsize = crypto_cipher_blocksize(tfm);
167
        unsigned int nbytes = walk->nbytes;
168
        u8 *src = walk->src.virt.addr;
169
        u8 *iv = walk->iv;
170
        u8 tmpbuf[bsize];
171
 
172
        do {
173
                memcpy(tmpbuf, src, bsize);
174
                fn(crypto_cipher_tfm(tfm), src, src);
175
                xor(src, iv, bsize);
176
                memcpy(iv, tmpbuf, bsize);
177
                xor(iv, src, bsize);
178
 
179
                src += bsize;
180
        } while ((nbytes -= bsize) >= bsize);
181
 
182
        memcpy(walk->iv, iv, bsize);
183
 
184
        return nbytes;
185
}
186
 
187
static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
188
                               struct scatterlist *dst, struct scatterlist *src,
189
                               unsigned int nbytes)
190
{
191
        struct blkcipher_walk walk;
192
        struct crypto_blkcipher *tfm = desc->tfm;
193
        struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
194
        struct crypto_cipher *child = ctx->child;
195
        void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
196
        int err;
197
 
198
        blkcipher_walk_init(&walk, dst, src, nbytes);
199
        err = blkcipher_walk_virt(desc, &walk);
200
 
201
        while ((nbytes = walk.nbytes)) {
202
                if (walk.src.virt.addr == walk.dst.virt.addr)
203
                        nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child,
204
                                                             xor);
205
                else
206
                        nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child,
207
                                                             xor);
208
                err = blkcipher_walk_done(desc, &walk, nbytes);
209
        }
210
 
211
        return err;
212
}
213
 
214
static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
215
{
216
        do {
217
                *a++ ^= *b++;
218
        } while (--bs);
219
}
220
 
221
static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
222
{
223
        u32 *a = (u32 *)dst;
224
        u32 *b = (u32 *)src;
225
 
226
        do {
227
                *a++ ^= *b++;
228
        } while ((bs -= 4));
229
}
230
 
231
static void xor_64(u8 *a, const u8 *b, unsigned int bs)
232
{
233
        ((u32 *)a)[0] ^= ((u32 *)b)[0];
234
        ((u32 *)a)[1] ^= ((u32 *)b)[1];
235
}
236
 
237
static void xor_128(u8 *a, const u8 *b, unsigned int bs)
238
{
239
        ((u32 *)a)[0] ^= ((u32 *)b)[0];
240
        ((u32 *)a)[1] ^= ((u32 *)b)[1];
241
        ((u32 *)a)[2] ^= ((u32 *)b)[2];
242
        ((u32 *)a)[3] ^= ((u32 *)b)[3];
243
}
244
 
245
static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
246
{
247
        struct crypto_instance *inst = (void *)tfm->__crt_alg;
248
        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
249
        struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
250
        struct crypto_cipher *cipher;
251
 
252
        switch (crypto_tfm_alg_blocksize(tfm)) {
253
        case 8:
254
                ctx->xor = xor_64;
255
                break;
256
 
257
        case 16:
258
                ctx->xor = xor_128;
259
                break;
260
 
261
        default:
262
                if (crypto_tfm_alg_blocksize(tfm) % 4)
263
                        ctx->xor = xor_byte;
264
                else
265
                        ctx->xor = xor_quad;
266
        }
267
 
268
        cipher = crypto_spawn_cipher(spawn);
269
        if (IS_ERR(cipher))
270
                return PTR_ERR(cipher);
271
 
272
        ctx->child = cipher;
273
        return 0;
274
}
275
 
276
static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm)
277
{
278
        struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
279
        crypto_free_cipher(ctx->child);
280
}
281
 
282
static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
283
{
284
        struct crypto_instance *inst;
285
        struct crypto_alg *alg;
286
        int err;
287
 
288
        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
289
        if (err)
290
                return ERR_PTR(err);
291
 
292
        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
293
                                  CRYPTO_ALG_TYPE_MASK);
294
        if (IS_ERR(alg))
295
                return ERR_PTR(PTR_ERR(alg));
296
 
297
        inst = crypto_alloc_instance("pcbc", alg);
298
        if (IS_ERR(inst))
299
                goto out_put_alg;
300
 
301
        inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
302
        inst->alg.cra_priority = alg->cra_priority;
303
        inst->alg.cra_blocksize = alg->cra_blocksize;
304
        inst->alg.cra_alignmask = alg->cra_alignmask;
305
        inst->alg.cra_type = &crypto_blkcipher_type;
306
 
307
        if (!(alg->cra_blocksize % 4))
308
                inst->alg.cra_alignmask |= 3;
309
        inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
310
        inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
311
        inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
312
 
313
        inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
314
 
315
        inst->alg.cra_init = crypto_pcbc_init_tfm;
316
        inst->alg.cra_exit = crypto_pcbc_exit_tfm;
317
 
318
        inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey;
319
        inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt;
320
        inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt;
321
 
322
out_put_alg:
323
        crypto_mod_put(alg);
324
        return inst;
325
}
326
 
327
static void crypto_pcbc_free(struct crypto_instance *inst)
328
{
329
        crypto_drop_spawn(crypto_instance_ctx(inst));
330
        kfree(inst);
331
}
332
 
333
static struct crypto_template crypto_pcbc_tmpl = {
334
        .name = "pcbc",
335
        .alloc = crypto_pcbc_alloc,
336
        .free = crypto_pcbc_free,
337
        .module = THIS_MODULE,
338
};
339
 
340
static int __init crypto_pcbc_module_init(void)
341
{
342
        return crypto_register_template(&crypto_pcbc_tmpl);
343
}
344
 
345
static void __exit crypto_pcbc_module_exit(void)
346
{
347
        crypto_unregister_template(&crypto_pcbc_tmpl);
348
}
349
 
350
module_init(crypto_pcbc_module_init);
351
module_exit(crypto_pcbc_module_exit);
352
 
353
MODULE_LICENSE("GPL");
354
MODULE_DESCRIPTION("PCBC block cipher algorithm");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.