11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Cryptographic API. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Cipher operations. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 7c774e93eSHerbert Xu * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 101da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the Free 111da177e4SLinus Torvalds * Software Foundation; either version 2 of the License, or (at your option) 121da177e4SLinus Torvalds * any later version. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds */ 15f1ddcaf3SHerbert Xu 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/crypto.h> 181da177e4SLinus Torvalds #include <linux/errno.h> 19f1ddcaf3SHerbert Xu #include <linux/scatterlist.h> 201da177e4SLinus Torvalds #include <linux/string.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 23*ca7c3938SSebastian Siewior static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 24*ca7c3938SSebastian Siewior { 25*ca7c3938SSebastian Siewior struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 26*ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 27*ca7c3938SSebastian Siewior int ret; 28*ca7c3938SSebastian Siewior u8 *buffer, *alignbuffer; 29*ca7c3938SSebastian Siewior unsigned long absize; 30*ca7c3938SSebastian Siewior 31*ca7c3938SSebastian Siewior absize = keylen + alignmask; 32*ca7c3938SSebastian Siewior buffer = kmalloc(absize, GFP_ATOMIC); 33*ca7c3938SSebastian Siewior if (!buffer) 34*ca7c3938SSebastian Siewior return -ENOMEM; 35*ca7c3938SSebastian Siewior 36*ca7c3938SSebastian Siewior alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 37*ca7c3938SSebastian Siewior memcpy(alignbuffer, key, keylen); 38*ca7c3938SSebastian Siewior ret = cia->cia_setkey(tfm, alignbuffer, keylen); 39*ca7c3938SSebastian Siewior memset(alignbuffer, 0, absize); 40*ca7c3938SSebastian Siewior kfree(buffer); 41*ca7c3938SSebastian Siewior return ret; 42*ca7c3938SSebastian Siewior 43*ca7c3938SSebastian Siewior } 44*ca7c3938SSebastian Siewior 451da177e4SLinus Torvalds static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 48*ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 491da177e4SLinus Torvalds 50560c06aeSHerbert Xu tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 511da177e4SLinus Torvalds if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { 521da177e4SLinus Torvalds tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 531da177e4SLinus Torvalds return -EINVAL; 54*ca7c3938SSebastian Siewior } 55*ca7c3938SSebastian Siewior 56*ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask) 57*ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen); 58*ca7c3938SSebastian Siewior 59560c06aeSHerbert Xu return cia->cia_setkey(tfm, key, keylen); 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 62f28776a3SHerbert Xu static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, 63f28776a3SHerbert Xu const u8 *), 64f28776a3SHerbert Xu struct crypto_tfm *tfm, 65f28776a3SHerbert Xu u8 *dst, const u8 *src) 66f28776a3SHerbert Xu { 67f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 68f28776a3SHerbert Xu unsigned int size = crypto_tfm_alg_blocksize(tfm); 69f28776a3SHerbert Xu u8 buffer[size + alignmask]; 70f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 71f28776a3SHerbert Xu 72f28776a3SHerbert Xu memcpy(tmp, src, size); 73f28776a3SHerbert Xu fn(tfm, tmp, tmp); 74f28776a3SHerbert Xu memcpy(dst, tmp, size); 75f28776a3SHerbert Xu } 76f28776a3SHerbert Xu 77f28776a3SHerbert Xu static void cipher_encrypt_unaligned(struct crypto_tfm *tfm, 78f28776a3SHerbert Xu u8 *dst, const u8 *src) 79f28776a3SHerbert Xu { 80f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 81f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 82f28776a3SHerbert Xu 83f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 84f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src); 85f28776a3SHerbert Xu return; 86f28776a3SHerbert Xu } 87f28776a3SHerbert Xu 88f28776a3SHerbert Xu cipher->cia_encrypt(tfm, dst, src); 89f28776a3SHerbert Xu } 90f28776a3SHerbert Xu 91f28776a3SHerbert Xu static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, 92f28776a3SHerbert Xu u8 *dst, const u8 *src) 93f28776a3SHerbert Xu { 94f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 95f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 96f28776a3SHerbert Xu 97f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 98f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src); 99f28776a3SHerbert Xu return; 100f28776a3SHerbert Xu } 101f28776a3SHerbert Xu 102f28776a3SHerbert Xu cipher->cia_decrypt(tfm, dst, src); 103f28776a3SHerbert Xu } 104f28776a3SHerbert Xu 1051da177e4SLinus Torvalds int crypto_init_cipher_ops(struct crypto_tfm *tfm) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds struct cipher_tfm *ops = &tfm->crt_cipher; 108f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds ops->cit_setkey = setkey; 111f28776a3SHerbert Xu ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ? 112f28776a3SHerbert Xu cipher_encrypt_unaligned : cipher->cia_encrypt; 113f28776a3SHerbert Xu ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? 114f28776a3SHerbert Xu cipher_decrypt_unaligned : cipher->cia_decrypt; 1151da177e4SLinus Torvalds 116f1ddcaf3SHerbert Xu return 0; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds void crypto_exit_cipher_ops(struct crypto_tfm *tfm) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds } 122