Back to home page

LXR

 
 

    


0001 /*
0002  * Cryptographic API.
0003  *
0004  * Cipher operations.
0005  *
0006  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
0007  * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
0008  *
0009  * This program is free software; you can redistribute it and/or modify it
0010  * under the terms of the GNU General Public License as published by the Free
0011  * Software Foundation; either version 2 of the License, or (at your option)
0012  * any later version.
0013  *
0014  */
0015 
0016 #include <linux/kernel.h>
0017 #include <linux/crypto.h>
0018 #include <linux/errno.h>
0019 #include <linux/slab.h>
0020 #include <linux/string.h>
0021 #include "internal.h"
0022 
0023 static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key,
0024                 unsigned int keylen)
0025 {
0026     struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
0027     unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
0028     int ret;
0029     u8 *buffer, *alignbuffer;
0030     unsigned long absize;
0031 
0032     absize = keylen + alignmask;
0033     buffer = kmalloc(absize, GFP_ATOMIC);
0034     if (!buffer)
0035         return -ENOMEM;
0036 
0037     alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
0038     memcpy(alignbuffer, key, keylen);
0039     ret = cia->cia_setkey(tfm, alignbuffer, keylen);
0040     memset(alignbuffer, 0, keylen);
0041     kfree(buffer);
0042     return ret;
0043 
0044 }
0045 
0046 static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
0047 {
0048     struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
0049     unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
0050 
0051     tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
0052     if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
0053         tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
0054         return -EINVAL;
0055     }
0056 
0057     if ((unsigned long)key & alignmask)
0058         return setkey_unaligned(tfm, key, keylen);
0059 
0060     return cia->cia_setkey(tfm, key, keylen);
0061 }
0062 
0063 static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
0064                           const u8 *),
0065                    struct crypto_tfm *tfm,
0066                    u8 *dst, const u8 *src)
0067 {
0068     unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
0069     unsigned int size = crypto_tfm_alg_blocksize(tfm);
0070     u8 buffer[size + alignmask];
0071     u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
0072 
0073     memcpy(tmp, src, size);
0074     fn(tfm, tmp, tmp);
0075     memcpy(dst, tmp, size);
0076 }
0077 
0078 static void cipher_encrypt_unaligned(struct crypto_tfm *tfm,
0079                      u8 *dst, const u8 *src)
0080 {
0081     unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
0082     struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
0083 
0084     if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
0085         cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src);
0086         return;
0087     }
0088 
0089     cipher->cia_encrypt(tfm, dst, src);
0090 }
0091 
0092 static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
0093                      u8 *dst, const u8 *src)
0094 {
0095     unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
0096     struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
0097 
0098     if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
0099         cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src);
0100         return;
0101     }
0102 
0103     cipher->cia_decrypt(tfm, dst, src);
0104 }
0105 
0106 int crypto_init_cipher_ops(struct crypto_tfm *tfm)
0107 {
0108     struct cipher_tfm *ops = &tfm->crt_cipher;
0109     struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
0110 
0111     ops->cit_setkey = setkey;
0112     ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ?
0113         cipher_encrypt_unaligned : cipher->cia_encrypt;
0114     ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
0115         cipher_decrypt_unaligned : cipher->cia_decrypt;
0116 
0117     return 0;
0118 }