1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Cryptographic API. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * 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 19791b4d5fSHerbert Xu static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, 20791b4d5fSHerbert Xu unsigned int keylen) 21ca7c3938SSebastian Siewior { 22ca7c3938SSebastian Siewior struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 23ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_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); 35ca7c3938SSebastian Siewior ret = cia->cia_setkey(tfm, alignbuffer, keylen); 3606817176SSebastian Siewior memset(alignbuffer, 0, keylen); 37ca7c3938SSebastian Siewior kfree(buffer); 38ca7c3938SSebastian Siewior return ret; 39ca7c3938SSebastian Siewior 40ca7c3938SSebastian Siewior } 41ca7c3938SSebastian Siewior 421da177e4SLinus Torvalds static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 45ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 461da177e4SLinus Torvalds 47560c06aeSHerbert Xu tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 481da177e4SLinus Torvalds if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { 491da177e4SLinus Torvalds tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 501da177e4SLinus Torvalds return -EINVAL; 51ca7c3938SSebastian Siewior } 52ca7c3938SSebastian Siewior 53ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask) 54ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen); 55ca7c3938SSebastian Siewior 56560c06aeSHerbert Xu return cia->cia_setkey(tfm, key, keylen); 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 59f28776a3SHerbert Xu static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, 60f28776a3SHerbert Xu const u8 *), 61f28776a3SHerbert Xu struct crypto_tfm *tfm, 62f28776a3SHerbert Xu u8 *dst, const u8 *src) 63f28776a3SHerbert Xu { 64f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 65f28776a3SHerbert Xu unsigned int size = crypto_tfm_alg_blocksize(tfm); 666650c4deSSalvatore Mesoraca u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; 67f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 68f28776a3SHerbert Xu 69f28776a3SHerbert Xu memcpy(tmp, src, size); 70f28776a3SHerbert Xu fn(tfm, tmp, tmp); 71f28776a3SHerbert Xu memcpy(dst, tmp, size); 72f28776a3SHerbert Xu } 73f28776a3SHerbert Xu 74f28776a3SHerbert Xu static void cipher_encrypt_unaligned(struct crypto_tfm *tfm, 75f28776a3SHerbert Xu u8 *dst, const u8 *src) 76f28776a3SHerbert Xu { 77f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 78f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 79f28776a3SHerbert Xu 80f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 81f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src); 82f28776a3SHerbert Xu return; 83f28776a3SHerbert Xu } 84f28776a3SHerbert Xu 85f28776a3SHerbert Xu cipher->cia_encrypt(tfm, dst, src); 86f28776a3SHerbert Xu } 87f28776a3SHerbert Xu 88f28776a3SHerbert Xu static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, 89f28776a3SHerbert Xu u8 *dst, const u8 *src) 90f28776a3SHerbert Xu { 91f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 92f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 93f28776a3SHerbert Xu 94f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 95f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src); 96f28776a3SHerbert Xu return; 97f28776a3SHerbert Xu } 98f28776a3SHerbert Xu 99f28776a3SHerbert Xu cipher->cia_decrypt(tfm, dst, src); 100f28776a3SHerbert Xu } 101f28776a3SHerbert Xu 1021da177e4SLinus Torvalds int crypto_init_cipher_ops(struct crypto_tfm *tfm) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds struct cipher_tfm *ops = &tfm->crt_cipher; 105f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds ops->cit_setkey = setkey; 108f28776a3SHerbert Xu ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ? 109f28776a3SHerbert Xu cipher_encrypt_unaligned : cipher->cia_encrypt; 110f28776a3SHerbert Xu ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? 111f28776a3SHerbert Xu cipher_decrypt_unaligned : cipher->cia_decrypt; 1121da177e4SLinus Torvalds 113f1ddcaf3SHerbert Xu return 0; 1141da177e4SLinus Torvalds } 115