12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Cryptographic API.
41da177e4SLinus Torvalds *
5e8cfed5eSEric Biggers * Single-block cipher operations.
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
8c774e93eSHerbert Xu * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
91da177e4SLinus Torvalds */
10f1ddcaf3SHerbert Xu
116650c4deSSalvatore Mesoraca #include <crypto/algapi.h>
120eb76ba2SArd Biesheuvel #include <crypto/internal/cipher.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/crypto.h>
151da177e4SLinus Torvalds #include <linux/errno.h>
16791b4d5fSHerbert Xu #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/string.h>
181da177e4SLinus Torvalds #include "internal.h"
191da177e4SLinus Torvalds
setkey_unaligned(struct crypto_cipher * tfm,const u8 * key,unsigned int keylen)20e8cfed5eSEric Biggers static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key,
21791b4d5fSHerbert Xu unsigned int keylen)
22ca7c3938SSebastian Siewior {
23e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm);
24e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm);
25ca7c3938SSebastian Siewior int ret;
26ca7c3938SSebastian Siewior u8 *buffer, *alignbuffer;
27ca7c3938SSebastian Siewior unsigned long absize;
28ca7c3938SSebastian Siewior
29ca7c3938SSebastian Siewior absize = keylen + alignmask;
30ca7c3938SSebastian Siewior buffer = kmalloc(absize, GFP_ATOMIC);
31ca7c3938SSebastian Siewior if (!buffer)
32ca7c3938SSebastian Siewior return -ENOMEM;
33ca7c3938SSebastian Siewior
34ca7c3938SSebastian Siewior alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
35ca7c3938SSebastian Siewior memcpy(alignbuffer, key, keylen);
36e8cfed5eSEric Biggers ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen);
3706817176SSebastian Siewior memset(alignbuffer, 0, keylen);
38ca7c3938SSebastian Siewior kfree(buffer);
39ca7c3938SSebastian Siewior return ret;
40ca7c3938SSebastian Siewior
41ca7c3938SSebastian Siewior }
42ca7c3938SSebastian Siewior
crypto_cipher_setkey(struct crypto_cipher * tfm,const u8 * key,unsigned int keylen)43e8cfed5eSEric Biggers int crypto_cipher_setkey(struct crypto_cipher *tfm,
44e8cfed5eSEric Biggers const u8 *key, unsigned int keylen)
451da177e4SLinus Torvalds {
46e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm);
47e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm);
481da177e4SLinus Torvalds
49674f368aSEric Biggers if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize)
501da177e4SLinus Torvalds return -EINVAL;
51ca7c3938SSebastian Siewior
52ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask)
53ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen);
54ca7c3938SSebastian Siewior
55e8cfed5eSEric Biggers return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen);
561da177e4SLinus Torvalds }
570eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, CRYPTO_INTERNAL);
581da177e4SLinus Torvalds
cipher_crypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src,bool enc)59e8cfed5eSEric Biggers static inline void cipher_crypt_one(struct crypto_cipher *tfm,
60e8cfed5eSEric Biggers u8 *dst, const u8 *src, bool enc)
61f28776a3SHerbert Xu {
62e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm);
63e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm);
64e8cfed5eSEric Biggers void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
65e8cfed5eSEric Biggers enc ? cia->cia_encrypt : cia->cia_decrypt;
66e8cfed5eSEric Biggers
67e8cfed5eSEric Biggers if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
68e8cfed5eSEric Biggers unsigned int bs = crypto_cipher_blocksize(tfm);
696650c4deSSalvatore Mesoraca u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
70f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
71f28776a3SHerbert Xu
72e8cfed5eSEric Biggers memcpy(tmp, src, bs);
73e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), tmp, tmp);
74e8cfed5eSEric Biggers memcpy(dst, tmp, bs);
75e8cfed5eSEric Biggers } else {
76e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), dst, src);
77e8cfed5eSEric Biggers }
78f28776a3SHerbert Xu }
79f28776a3SHerbert Xu
crypto_cipher_encrypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src)80e8cfed5eSEric Biggers void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
81f28776a3SHerbert Xu u8 *dst, const u8 *src)
82f28776a3SHerbert Xu {
83e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, true);
84f28776a3SHerbert Xu }
850eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, CRYPTO_INTERNAL);
86f28776a3SHerbert Xu
crypto_cipher_decrypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src)87e8cfed5eSEric Biggers void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
88f28776a3SHerbert Xu u8 *dst, const u8 *src)
89f28776a3SHerbert Xu {
90e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, false);
91f28776a3SHerbert Xu }
920eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, CRYPTO_INTERNAL);
9351d8d6d0SHerbert Xu
crypto_clone_cipher(struct crypto_cipher * cipher)9451d8d6d0SHerbert Xu struct crypto_cipher *crypto_clone_cipher(struct crypto_cipher *cipher)
9551d8d6d0SHerbert Xu {
9651d8d6d0SHerbert Xu struct crypto_tfm *tfm = crypto_cipher_tfm(cipher);
9751d8d6d0SHerbert Xu struct crypto_alg *alg = tfm->__crt_alg;
9851d8d6d0SHerbert Xu struct crypto_cipher *ncipher;
9951d8d6d0SHerbert Xu struct crypto_tfm *ntfm;
10051d8d6d0SHerbert Xu
10151d8d6d0SHerbert Xu if (alg->cra_init)
10251d8d6d0SHerbert Xu return ERR_PTR(-ENOSYS);
10351d8d6d0SHerbert Xu
104*9979c6e5SDmitry Safonov if (unlikely(!crypto_mod_get(alg)))
105*9979c6e5SDmitry Safonov return ERR_PTR(-ESTALE);
106*9979c6e5SDmitry Safonov
107fa3b3565SHerbert Xu ntfm = __crypto_alloc_tfmgfp(alg, CRYPTO_ALG_TYPE_CIPHER,
108fa3b3565SHerbert Xu CRYPTO_ALG_TYPE_MASK, GFP_ATOMIC);
109*9979c6e5SDmitry Safonov if (IS_ERR(ntfm)) {
110*9979c6e5SDmitry Safonov crypto_mod_put(alg);
11151d8d6d0SHerbert Xu return ERR_CAST(ntfm);
112*9979c6e5SDmitry Safonov }
11351d8d6d0SHerbert Xu
11451d8d6d0SHerbert Xu ntfm->crt_flags = tfm->crt_flags;
11551d8d6d0SHerbert Xu
11651d8d6d0SHerbert Xu ncipher = __crypto_cipher_cast(ntfm);
11751d8d6d0SHerbert Xu
11851d8d6d0SHerbert Xu return ncipher;
11951d8d6d0SHerbert Xu }
12051d8d6d0SHerbert Xu EXPORT_SYMBOL_GPL(crypto_clone_cipher);
121