Back to home page

LXR

 
 

    


0001 /*
0002  * PCBC: Propagating Cipher Block Chaining mode
0003  *
0004  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  *
0007  * Derived from cbc.c
0008  * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
0009  *
0010  * This program is free software; you can redistribute it and/or modify it
0011  * under the terms of the GNU General Public License as published by the Free
0012  * Software Foundation; either version 2 of the License, or (at your option)
0013  * any later version.
0014  *
0015  */
0016 
0017 #include <crypto/internal/skcipher.h>
0018 #include <linux/err.h>
0019 #include <linux/init.h>
0020 #include <linux/kernel.h>
0021 #include <linux/module.h>
0022 #include <linux/slab.h>
0023 
0024 struct crypto_pcbc_ctx {
0025     struct crypto_cipher *child;
0026 };
0027 
0028 static int crypto_pcbc_setkey(struct crypto_skcipher *parent, const u8 *key,
0029                   unsigned int keylen)
0030 {
0031     struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(parent);
0032     struct crypto_cipher *child = ctx->child;
0033     int err;
0034 
0035     crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
0036     crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
0037                        CRYPTO_TFM_REQ_MASK);
0038     err = crypto_cipher_setkey(child, key, keylen);
0039     crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
0040                       CRYPTO_TFM_RES_MASK);
0041     return err;
0042 }
0043 
0044 static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
0045                        struct skcipher_walk *walk,
0046                        struct crypto_cipher *tfm)
0047 {
0048     int bsize = crypto_cipher_blocksize(tfm);
0049     unsigned int nbytes = walk->nbytes;
0050     u8 *src = walk->src.virt.addr;
0051     u8 *dst = walk->dst.virt.addr;
0052     u8 *iv = walk->iv;
0053 
0054     do {
0055         crypto_xor(iv, src, bsize);
0056         crypto_cipher_encrypt_one(tfm, dst, iv);
0057         memcpy(iv, dst, bsize);
0058         crypto_xor(iv, src, bsize);
0059 
0060         src += bsize;
0061         dst += bsize;
0062     } while ((nbytes -= bsize) >= bsize);
0063 
0064     return nbytes;
0065 }
0066 
0067 static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
0068                        struct skcipher_walk *walk,
0069                        struct crypto_cipher *tfm)
0070 {
0071     int bsize = crypto_cipher_blocksize(tfm);
0072     unsigned int nbytes = walk->nbytes;
0073     u8 *src = walk->src.virt.addr;
0074     u8 *iv = walk->iv;
0075     u8 tmpbuf[bsize];
0076 
0077     do {
0078         memcpy(tmpbuf, src, bsize);
0079         crypto_xor(iv, src, bsize);
0080         crypto_cipher_encrypt_one(tfm, src, iv);
0081         memcpy(iv, tmpbuf, bsize);
0082         crypto_xor(iv, src, bsize);
0083 
0084         src += bsize;
0085     } while ((nbytes -= bsize) >= bsize);
0086 
0087     memcpy(walk->iv, iv, bsize);
0088 
0089     return nbytes;
0090 }
0091 
0092 static int crypto_pcbc_encrypt(struct skcipher_request *req)
0093 {
0094     struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0095     struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
0096     struct crypto_cipher *child = ctx->child;
0097     struct skcipher_walk walk;
0098     unsigned int nbytes;
0099     int err;
0100 
0101     err = skcipher_walk_virt(&walk, req, false);
0102 
0103     while ((nbytes = walk.nbytes)) {
0104         if (walk.src.virt.addr == walk.dst.virt.addr)
0105             nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
0106                                  child);
0107         else
0108             nbytes = crypto_pcbc_encrypt_segment(req, &walk,
0109                                  child);
0110         err = skcipher_walk_done(&walk, nbytes);
0111     }
0112 
0113     return err;
0114 }
0115 
0116 static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
0117                        struct skcipher_walk *walk,
0118                        struct crypto_cipher *tfm)
0119 {
0120     int bsize = crypto_cipher_blocksize(tfm);
0121     unsigned int nbytes = walk->nbytes;
0122     u8 *src = walk->src.virt.addr;
0123     u8 *dst = walk->dst.virt.addr;
0124     u8 *iv = walk->iv;
0125 
0126     do {
0127         crypto_cipher_decrypt_one(tfm, dst, src);
0128         crypto_xor(dst, iv, bsize);
0129         memcpy(iv, src, bsize);
0130         crypto_xor(iv, dst, bsize);
0131 
0132         src += bsize;
0133         dst += bsize;
0134     } while ((nbytes -= bsize) >= bsize);
0135 
0136     memcpy(walk->iv, iv, bsize);
0137 
0138     return nbytes;
0139 }
0140 
0141 static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
0142                        struct skcipher_walk *walk,
0143                        struct crypto_cipher *tfm)
0144 {
0145     int bsize = crypto_cipher_blocksize(tfm);
0146     unsigned int nbytes = walk->nbytes;
0147     u8 *src = walk->src.virt.addr;
0148     u8 *iv = walk->iv;
0149     u8 tmpbuf[bsize] __attribute__ ((aligned(__alignof__(u32))));
0150 
0151     do {
0152         memcpy(tmpbuf, src, bsize);
0153         crypto_cipher_decrypt_one(tfm, src, src);
0154         crypto_xor(src, iv, bsize);
0155         memcpy(iv, tmpbuf, bsize);
0156         crypto_xor(iv, src, bsize);
0157 
0158         src += bsize;
0159     } while ((nbytes -= bsize) >= bsize);
0160 
0161     memcpy(walk->iv, iv, bsize);
0162 
0163     return nbytes;
0164 }
0165 
0166 static int crypto_pcbc_decrypt(struct skcipher_request *req)
0167 {
0168     struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0169     struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
0170     struct crypto_cipher *child = ctx->child;
0171     struct skcipher_walk walk;
0172     unsigned int nbytes;
0173     int err;
0174 
0175     err = skcipher_walk_virt(&walk, req, false);
0176 
0177     while ((nbytes = walk.nbytes)) {
0178         if (walk.src.virt.addr == walk.dst.virt.addr)
0179             nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
0180                                  child);
0181         else
0182             nbytes = crypto_pcbc_decrypt_segment(req, &walk,
0183                                  child);
0184         err = skcipher_walk_done(&walk, nbytes);
0185     }
0186 
0187     return err;
0188 }
0189 
0190 static int crypto_pcbc_init_tfm(struct crypto_skcipher *tfm)
0191 {
0192     struct skcipher_instance *inst = skcipher_alg_instance(tfm);
0193     struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
0194     struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
0195     struct crypto_cipher *cipher;
0196 
0197     cipher = crypto_spawn_cipher(spawn);
0198     if (IS_ERR(cipher))
0199         return PTR_ERR(cipher);
0200 
0201     ctx->child = cipher;
0202     return 0;
0203 }
0204 
0205 static void crypto_pcbc_exit_tfm(struct crypto_skcipher *tfm)
0206 {
0207     struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
0208 
0209     crypto_free_cipher(ctx->child);
0210 }
0211 
0212 static void crypto_pcbc_free(struct skcipher_instance *inst)
0213 {
0214     crypto_drop_skcipher(skcipher_instance_ctx(inst));
0215     kfree(inst);
0216 }
0217 
0218 static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
0219 {
0220     struct skcipher_instance *inst;
0221     struct crypto_attr_type *algt;
0222     struct crypto_spawn *spawn;
0223     struct crypto_alg *alg;
0224     int err;
0225 
0226     algt = crypto_get_attr_type(tb);
0227     if (IS_ERR(algt))
0228         return PTR_ERR(algt);
0229 
0230     if (((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) &
0231         ~CRYPTO_ALG_INTERNAL)
0232         return -EINVAL;
0233 
0234     inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
0235     if (!inst)
0236         return -ENOMEM;
0237 
0238     alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER |
0239                       (algt->type & CRYPTO_ALG_INTERNAL),
0240                   CRYPTO_ALG_TYPE_MASK |
0241                   (algt->mask & CRYPTO_ALG_INTERNAL));
0242     err = PTR_ERR(alg);
0243     if (IS_ERR(alg))
0244         goto err_free_inst;
0245 
0246     spawn = skcipher_instance_ctx(inst);
0247     err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
0248                 CRYPTO_ALG_TYPE_MASK);
0249     crypto_mod_put(alg);
0250     if (err)
0251         goto err_free_inst;
0252 
0253     err = crypto_inst_setname(skcipher_crypto_instance(inst), "pcbc", alg);
0254     if (err)
0255         goto err_drop_spawn;
0256 
0257     inst->alg.base.cra_flags = alg->cra_flags & CRYPTO_ALG_INTERNAL;
0258     inst->alg.base.cra_priority = alg->cra_priority;
0259     inst->alg.base.cra_blocksize = alg->cra_blocksize;
0260     inst->alg.base.cra_alignmask = alg->cra_alignmask;
0261 
0262     /* We access the data as u32s when xoring. */
0263     inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
0264 
0265     inst->alg.ivsize = alg->cra_blocksize;
0266     inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
0267     inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
0268 
0269     inst->alg.base.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
0270 
0271     inst->alg.init = crypto_pcbc_init_tfm;
0272     inst->alg.exit = crypto_pcbc_exit_tfm;
0273 
0274     inst->alg.setkey = crypto_pcbc_setkey;
0275     inst->alg.encrypt = crypto_pcbc_encrypt;
0276     inst->alg.decrypt = crypto_pcbc_decrypt;
0277 
0278     inst->free = crypto_pcbc_free;
0279 
0280     err = skcipher_register_instance(tmpl, inst);
0281     if (err)
0282         goto err_drop_spawn;
0283 
0284 out:
0285     return err;
0286 
0287 err_drop_spawn:
0288     crypto_drop_spawn(spawn);
0289 err_free_inst:
0290     kfree(inst);
0291     goto out;
0292 }
0293 
0294 static struct crypto_template crypto_pcbc_tmpl = {
0295     .name = "pcbc",
0296     .create = crypto_pcbc_create,
0297     .module = THIS_MODULE,
0298 };
0299 
0300 static int __init crypto_pcbc_module_init(void)
0301 {
0302     return crypto_register_template(&crypto_pcbc_tmpl);
0303 }
0304 
0305 static void __exit crypto_pcbc_module_exit(void)
0306 {
0307     crypto_unregister_template(&crypto_pcbc_tmpl);
0308 }
0309 
0310 module_init(crypto_pcbc_module_init);
0311 module_exit(crypto_pcbc_module_exit);
0312 
0313 MODULE_LICENSE("GPL");
0314 MODULE_DESCRIPTION("PCBC block cipher algorithm");
0315 MODULE_ALIAS_CRYPTO("pcbc");