162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cryptographic API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Single-block cipher operations. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 862306a36Sopenharmony_ci * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/algapi.h> 1262306a36Sopenharmony_ci#include <crypto/internal/cipher.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/crypto.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/string.h> 1862306a36Sopenharmony_ci#include "internal.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key, 2162306a36Sopenharmony_ci unsigned int keylen) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct cipher_alg *cia = crypto_cipher_alg(tfm); 2462306a36Sopenharmony_ci unsigned long alignmask = crypto_cipher_alignmask(tfm); 2562306a36Sopenharmony_ci int ret; 2662306a36Sopenharmony_ci u8 *buffer, *alignbuffer; 2762306a36Sopenharmony_ci unsigned long absize; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci absize = keylen + alignmask; 3062306a36Sopenharmony_ci buffer = kmalloc(absize, GFP_ATOMIC); 3162306a36Sopenharmony_ci if (!buffer) 3262306a36Sopenharmony_ci return -ENOMEM; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 3562306a36Sopenharmony_ci memcpy(alignbuffer, key, keylen); 3662306a36Sopenharmony_ci ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen); 3762306a36Sopenharmony_ci memset(alignbuffer, 0, keylen); 3862306a36Sopenharmony_ci kfree(buffer); 3962306a36Sopenharmony_ci return ret; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciint crypto_cipher_setkey(struct crypto_cipher *tfm, 4462306a36Sopenharmony_ci const u8 *key, unsigned int keylen) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct cipher_alg *cia = crypto_cipher_alg(tfm); 4762306a36Sopenharmony_ci unsigned long alignmask = crypto_cipher_alignmask(tfm); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) 5062306a36Sopenharmony_ci return -EINVAL; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if ((unsigned long)key & alignmask) 5362306a36Sopenharmony_ci return setkey_unaligned(tfm, key, keylen); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, CRYPTO_INTERNAL); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline void cipher_crypt_one(struct crypto_cipher *tfm, 6062306a36Sopenharmony_ci u8 *dst, const u8 *src, bool enc) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci unsigned long alignmask = crypto_cipher_alignmask(tfm); 6362306a36Sopenharmony_ci struct cipher_alg *cia = crypto_cipher_alg(tfm); 6462306a36Sopenharmony_ci void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = 6562306a36Sopenharmony_ci enc ? cia->cia_encrypt : cia->cia_decrypt; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 6862306a36Sopenharmony_ci unsigned int bs = crypto_cipher_blocksize(tfm); 6962306a36Sopenharmony_ci u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; 7062306a36Sopenharmony_ci u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci memcpy(tmp, src, bs); 7362306a36Sopenharmony_ci fn(crypto_cipher_tfm(tfm), tmp, tmp); 7462306a36Sopenharmony_ci memcpy(dst, tmp, bs); 7562306a36Sopenharmony_ci } else { 7662306a36Sopenharmony_ci fn(crypto_cipher_tfm(tfm), dst, src); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid crypto_cipher_encrypt_one(struct crypto_cipher *tfm, 8162306a36Sopenharmony_ci u8 *dst, const u8 *src) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci cipher_crypt_one(tfm, dst, src, true); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, CRYPTO_INTERNAL); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_civoid crypto_cipher_decrypt_one(struct crypto_cipher *tfm, 8862306a36Sopenharmony_ci u8 *dst, const u8 *src) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci cipher_crypt_one(tfm, dst, src, false); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, CRYPTO_INTERNAL); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct crypto_cipher *crypto_clone_cipher(struct crypto_cipher *cipher) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct crypto_tfm *tfm = crypto_cipher_tfm(cipher); 9762306a36Sopenharmony_ci struct crypto_alg *alg = tfm->__crt_alg; 9862306a36Sopenharmony_ci struct crypto_cipher *ncipher; 9962306a36Sopenharmony_ci struct crypto_tfm *ntfm; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (alg->cra_init) 10262306a36Sopenharmony_ci return ERR_PTR(-ENOSYS); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (unlikely(!crypto_mod_get(alg))) 10562306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci ntfm = __crypto_alloc_tfmgfp(alg, CRYPTO_ALG_TYPE_CIPHER, 10862306a36Sopenharmony_ci CRYPTO_ALG_TYPE_MASK, GFP_ATOMIC); 10962306a36Sopenharmony_ci if (IS_ERR(ntfm)) { 11062306a36Sopenharmony_ci crypto_mod_put(alg); 11162306a36Sopenharmony_ci return ERR_CAST(ntfm); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ntfm->crt_flags = tfm->crt_flags; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ncipher = __crypto_cipher_cast(ntfm); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return ncipher; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_clone_cipher); 121