Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Cryptographic API.
0004  *
0005  * Single-block cipher operations.
0006  *
0007  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
0008  * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
0009  */
0010 
0011 #include <crypto/algapi.h>
0012 #include <crypto/internal/cipher.h>
0013 #include <linux/kernel.h>
0014 #include <linux/crypto.h>
0015 #include <linux/errno.h>
0016 #include <linux/slab.h>
0017 #include <linux/string.h>
0018 #include "internal.h"
0019 
0020 static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key,
0021                 unsigned int keylen)
0022 {
0023     struct cipher_alg *cia = crypto_cipher_alg(tfm);
0024     unsigned long alignmask = crypto_cipher_alignmask(tfm);
0025     int ret;
0026     u8 *buffer, *alignbuffer;
0027     unsigned long absize;
0028 
0029     absize = keylen + alignmask;
0030     buffer = kmalloc(absize, GFP_ATOMIC);
0031     if (!buffer)
0032         return -ENOMEM;
0033 
0034     alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
0035     memcpy(alignbuffer, key, keylen);
0036     ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen);
0037     memset(alignbuffer, 0, keylen);
0038     kfree(buffer);
0039     return ret;
0040 
0041 }
0042 
0043 int crypto_cipher_setkey(struct crypto_cipher *tfm,
0044              const u8 *key, unsigned int keylen)
0045 {
0046     struct cipher_alg *cia = crypto_cipher_alg(tfm);
0047     unsigned long alignmask = crypto_cipher_alignmask(tfm);
0048 
0049     if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize)
0050         return -EINVAL;
0051 
0052     if ((unsigned long)key & alignmask)
0053         return setkey_unaligned(tfm, key, keylen);
0054 
0055     return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen);
0056 }
0057 EXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, CRYPTO_INTERNAL);
0058 
0059 static inline void cipher_crypt_one(struct crypto_cipher *tfm,
0060                     u8 *dst, const u8 *src, bool enc)
0061 {
0062     unsigned long alignmask = crypto_cipher_alignmask(tfm);
0063     struct cipher_alg *cia = crypto_cipher_alg(tfm);
0064     void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
0065         enc ? cia->cia_encrypt : cia->cia_decrypt;
0066 
0067     if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
0068         unsigned int bs = crypto_cipher_blocksize(tfm);
0069         u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
0070         u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
0071 
0072         memcpy(tmp, src, bs);
0073         fn(crypto_cipher_tfm(tfm), tmp, tmp);
0074         memcpy(dst, tmp, bs);
0075     } else {
0076         fn(crypto_cipher_tfm(tfm), dst, src);
0077     }
0078 }
0079 
0080 void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
0081                    u8 *dst, const u8 *src)
0082 {
0083     cipher_crypt_one(tfm, dst, src, true);
0084 }
0085 EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, CRYPTO_INTERNAL);
0086 
0087 void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
0088                    u8 *dst, const u8 *src)
0089 {
0090     cipher_crypt_one(tfm, dst, src, false);
0091 }
0092 EXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, CRYPTO_INTERNAL);