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);
37*b502d4a0SHailey Mothershead kfree_sensitive(buffer);
38ca7c3938SSebastian Siewior return ret;
39ca7c3938SSebastian Siewior
40ca7c3938SSebastian Siewior }
41ca7c3938SSebastian Siewior
crypto_cipher_setkey(struct crypto_cipher * tfm,const u8 * key,unsigned int keylen)42e8cfed5eSEric Biggers int crypto_cipher_setkey(struct crypto_cipher *tfm,
43e8cfed5eSEric Biggers const u8 *key, unsigned int keylen)
441da177e4SLinus Torvalds {
45e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm);
46e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm);
471da177e4SLinus Torvalds
48674f368aSEric Biggers if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize)
491da177e4SLinus Torvalds return -EINVAL;
50ca7c3938SSebastian Siewior
51ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask)
52ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen);
53ca7c3938SSebastian Siewior
54e8cfed5eSEric Biggers return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen);
551da177e4SLinus Torvalds }
560eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, CRYPTO_INTERNAL);
571da177e4SLinus Torvalds
cipher_crypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src,bool enc)58e8cfed5eSEric Biggers static inline void cipher_crypt_one(struct crypto_cipher *tfm,
59e8cfed5eSEric Biggers u8 *dst, const u8 *src, bool enc)
60f28776a3SHerbert Xu {
61e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm);
62e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm);
63e8cfed5eSEric Biggers void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
64e8cfed5eSEric Biggers enc ? cia->cia_encrypt : cia->cia_decrypt;
65e8cfed5eSEric Biggers
66e8cfed5eSEric Biggers if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
67e8cfed5eSEric Biggers unsigned int bs = crypto_cipher_blocksize(tfm);
686650c4deSSalvatore Mesoraca u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
69f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
70f28776a3SHerbert Xu
71e8cfed5eSEric Biggers memcpy(tmp, src, bs);
72e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), tmp, tmp);
73e8cfed5eSEric Biggers memcpy(dst, tmp, bs);
74e8cfed5eSEric Biggers } else {
75e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), dst, src);
76e8cfed5eSEric Biggers }
77f28776a3SHerbert Xu }
78f28776a3SHerbert Xu
crypto_cipher_encrypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src)79e8cfed5eSEric Biggers void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
80f28776a3SHerbert Xu u8 *dst, const u8 *src)
81f28776a3SHerbert Xu {
82e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, true);
83f28776a3SHerbert Xu }
840eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, CRYPTO_INTERNAL);
85f28776a3SHerbert Xu
crypto_cipher_decrypt_one(struct crypto_cipher * tfm,u8 * dst,const u8 * src)86e8cfed5eSEric Biggers void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
87f28776a3SHerbert Xu u8 *dst, const u8 *src)
88f28776a3SHerbert Xu {
89e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, false);
90f28776a3SHerbert Xu }
910eb76ba2SArd Biesheuvel EXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, CRYPTO_INTERNAL);
9251d8d6d0SHerbert Xu
crypto_clone_cipher(struct crypto_cipher * cipher)9351d8d6d0SHerbert Xu struct crypto_cipher *crypto_clone_cipher(struct crypto_cipher *cipher)
9451d8d6d0SHerbert Xu {
9551d8d6d0SHerbert Xu struct crypto_tfm *tfm = crypto_cipher_tfm(cipher);
9651d8d6d0SHerbert Xu struct crypto_alg *alg = tfm->__crt_alg;
9751d8d6d0SHerbert Xu struct crypto_cipher *ncipher;
9851d8d6d0SHerbert Xu struct crypto_tfm *ntfm;
9951d8d6d0SHerbert Xu
10051d8d6d0SHerbert Xu if (alg->cra_init)
10151d8d6d0SHerbert Xu return ERR_PTR(-ENOSYS);
10251d8d6d0SHerbert Xu
1039979c6e5SDmitry Safonov if (unlikely(!crypto_mod_get(alg)))
1049979c6e5SDmitry Safonov return ERR_PTR(-ESTALE);
1059979c6e5SDmitry Safonov
106fa3b3565SHerbert Xu ntfm = __crypto_alloc_tfmgfp(alg, CRYPTO_ALG_TYPE_CIPHER,
107fa3b3565SHerbert Xu CRYPTO_ALG_TYPE_MASK, GFP_ATOMIC);
1089979c6e5SDmitry Safonov if (IS_ERR(ntfm)) {
1099979c6e5SDmitry Safonov crypto_mod_put(alg);
11051d8d6d0SHerbert Xu return ERR_CAST(ntfm);
1119979c6e5SDmitry Safonov }
11251d8d6d0SHerbert Xu
11351d8d6d0SHerbert Xu ntfm->crt_flags = tfm->crt_flags;
11451d8d6d0SHerbert Xu
11551d8d6d0SHerbert Xu ncipher = __crypto_cipher_cast(ntfm);
11651d8d6d0SHerbert Xu
11751d8d6d0SHerbert Xu return ncipher;
11851d8d6d0SHerbert Xu }
11951d8d6d0SHerbert Xu EXPORT_SYMBOL_GPL(crypto_clone_cipher);
120