12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Cryptographic API. 41da177e4SLinus Torvalds * 5*e8cfed5eSEric 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> 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/crypto.h> 141da177e4SLinus Torvalds #include <linux/errno.h> 15791b4d5fSHerbert Xu #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/string.h> 171da177e4SLinus Torvalds #include "internal.h" 181da177e4SLinus Torvalds 19*e8cfed5eSEric Biggers static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key, 20791b4d5fSHerbert Xu unsigned int keylen) 21ca7c3938SSebastian Siewior { 22*e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm); 23*e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm); 24ca7c3938SSebastian Siewior int ret; 25ca7c3938SSebastian Siewior u8 *buffer, *alignbuffer; 26ca7c3938SSebastian Siewior unsigned long absize; 27ca7c3938SSebastian Siewior 28ca7c3938SSebastian Siewior absize = keylen + alignmask; 29ca7c3938SSebastian Siewior buffer = kmalloc(absize, GFP_ATOMIC); 30ca7c3938SSebastian Siewior if (!buffer) 31ca7c3938SSebastian Siewior return -ENOMEM; 32ca7c3938SSebastian Siewior 33ca7c3938SSebastian Siewior alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 34ca7c3938SSebastian Siewior memcpy(alignbuffer, key, keylen); 35*e8cfed5eSEric Biggers ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen); 3606817176SSebastian Siewior memset(alignbuffer, 0, keylen); 37ca7c3938SSebastian Siewior kfree(buffer); 38ca7c3938SSebastian Siewior return ret; 39ca7c3938SSebastian Siewior 40ca7c3938SSebastian Siewior } 41ca7c3938SSebastian Siewior 42*e8cfed5eSEric Biggers int crypto_cipher_setkey(struct crypto_cipher *tfm, 43*e8cfed5eSEric Biggers const u8 *key, unsigned int keylen) 441da177e4SLinus Torvalds { 45*e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm); 46*e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm); 471da177e4SLinus Torvalds 48*e8cfed5eSEric Biggers crypto_cipher_clear_flags(tfm, CRYPTO_TFM_RES_MASK); 491da177e4SLinus Torvalds if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { 50*e8cfed5eSEric Biggers crypto_cipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 511da177e4SLinus Torvalds return -EINVAL; 52ca7c3938SSebastian Siewior } 53ca7c3938SSebastian Siewior 54ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask) 55ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen); 56ca7c3938SSebastian Siewior 57*e8cfed5eSEric Biggers return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen); 581da177e4SLinus Torvalds } 59*e8cfed5eSEric Biggers EXPORT_SYMBOL_GPL(crypto_cipher_setkey); 601da177e4SLinus Torvalds 61*e8cfed5eSEric Biggers static inline void cipher_crypt_one(struct crypto_cipher *tfm, 62*e8cfed5eSEric Biggers u8 *dst, const u8 *src, bool enc) 63f28776a3SHerbert Xu { 64*e8cfed5eSEric Biggers unsigned long alignmask = crypto_cipher_alignmask(tfm); 65*e8cfed5eSEric Biggers struct cipher_alg *cia = crypto_cipher_alg(tfm); 66*e8cfed5eSEric Biggers void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = 67*e8cfed5eSEric Biggers enc ? cia->cia_encrypt : cia->cia_decrypt; 68*e8cfed5eSEric Biggers 69*e8cfed5eSEric Biggers if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 70*e8cfed5eSEric Biggers unsigned int bs = crypto_cipher_blocksize(tfm); 716650c4deSSalvatore Mesoraca u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; 72f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 73f28776a3SHerbert Xu 74*e8cfed5eSEric Biggers memcpy(tmp, src, bs); 75*e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), tmp, tmp); 76*e8cfed5eSEric Biggers memcpy(dst, tmp, bs); 77*e8cfed5eSEric Biggers } else { 78*e8cfed5eSEric Biggers fn(crypto_cipher_tfm(tfm), dst, src); 79*e8cfed5eSEric Biggers } 80f28776a3SHerbert Xu } 81f28776a3SHerbert Xu 82*e8cfed5eSEric Biggers void crypto_cipher_encrypt_one(struct crypto_cipher *tfm, 83f28776a3SHerbert Xu u8 *dst, const u8 *src) 84f28776a3SHerbert Xu { 85*e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, true); 86f28776a3SHerbert Xu } 87*e8cfed5eSEric Biggers EXPORT_SYMBOL_GPL(crypto_cipher_encrypt_one); 88f28776a3SHerbert Xu 89*e8cfed5eSEric Biggers void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, 90f28776a3SHerbert Xu u8 *dst, const u8 *src) 91f28776a3SHerbert Xu { 92*e8cfed5eSEric Biggers cipher_crypt_one(tfm, dst, src, false); 93f28776a3SHerbert Xu } 94*e8cfed5eSEric Biggers EXPORT_SYMBOL_GPL(crypto_cipher_decrypt_one); 95