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> 19*791b4d5fSHerbert Xu #include <linux/slab.h> 201da177e4SLinus Torvalds #include <linux/string.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 23*791b4d5fSHerbert Xu static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, 24*791b4d5fSHerbert Xu unsigned int keylen) 25ca7c3938SSebastian Siewior { 26ca7c3938SSebastian Siewior struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 27ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 28ca7c3938SSebastian Siewior int ret; 29ca7c3938SSebastian Siewior u8 *buffer, *alignbuffer; 30ca7c3938SSebastian Siewior unsigned long absize; 31ca7c3938SSebastian Siewior 32ca7c3938SSebastian Siewior absize = keylen + alignmask; 33ca7c3938SSebastian Siewior buffer = kmalloc(absize, GFP_ATOMIC); 34ca7c3938SSebastian Siewior if (!buffer) 35ca7c3938SSebastian Siewior return -ENOMEM; 36ca7c3938SSebastian Siewior 37ca7c3938SSebastian Siewior alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 38ca7c3938SSebastian Siewior memcpy(alignbuffer, key, keylen); 39ca7c3938SSebastian Siewior ret = cia->cia_setkey(tfm, alignbuffer, keylen); 4006817176SSebastian Siewior memset(alignbuffer, 0, keylen); 41ca7c3938SSebastian Siewior kfree(buffer); 42ca7c3938SSebastian Siewior return ret; 43ca7c3938SSebastian Siewior 44ca7c3938SSebastian Siewior } 45ca7c3938SSebastian Siewior 461da177e4SLinus Torvalds static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; 49ca7c3938SSebastian Siewior unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 501da177e4SLinus Torvalds 51560c06aeSHerbert Xu tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; 521da177e4SLinus Torvalds if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { 531da177e4SLinus Torvalds tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 541da177e4SLinus Torvalds return -EINVAL; 55ca7c3938SSebastian Siewior } 56ca7c3938SSebastian Siewior 57ca7c3938SSebastian Siewior if ((unsigned long)key & alignmask) 58ca7c3938SSebastian Siewior return setkey_unaligned(tfm, key, keylen); 59ca7c3938SSebastian Siewior 60560c06aeSHerbert Xu return cia->cia_setkey(tfm, key, keylen); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 63f28776a3SHerbert Xu static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, 64f28776a3SHerbert Xu const u8 *), 65f28776a3SHerbert Xu struct crypto_tfm *tfm, 66f28776a3SHerbert Xu u8 *dst, const u8 *src) 67f28776a3SHerbert Xu { 68f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 69f28776a3SHerbert Xu unsigned int size = crypto_tfm_alg_blocksize(tfm); 70f28776a3SHerbert Xu u8 buffer[size + alignmask]; 71f28776a3SHerbert Xu u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 72f28776a3SHerbert Xu 73f28776a3SHerbert Xu memcpy(tmp, src, size); 74f28776a3SHerbert Xu fn(tfm, tmp, tmp); 75f28776a3SHerbert Xu memcpy(dst, tmp, size); 76f28776a3SHerbert Xu } 77f28776a3SHerbert Xu 78f28776a3SHerbert Xu static void cipher_encrypt_unaligned(struct crypto_tfm *tfm, 79f28776a3SHerbert Xu u8 *dst, const u8 *src) 80f28776a3SHerbert Xu { 81f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 82f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 83f28776a3SHerbert Xu 84f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 85f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src); 86f28776a3SHerbert Xu return; 87f28776a3SHerbert Xu } 88f28776a3SHerbert Xu 89f28776a3SHerbert Xu cipher->cia_encrypt(tfm, dst, src); 90f28776a3SHerbert Xu } 91f28776a3SHerbert Xu 92f28776a3SHerbert Xu static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, 93f28776a3SHerbert Xu u8 *dst, const u8 *src) 94f28776a3SHerbert Xu { 95f28776a3SHerbert Xu unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 96f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 97f28776a3SHerbert Xu 98f28776a3SHerbert Xu if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { 99f28776a3SHerbert Xu cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src); 100f28776a3SHerbert Xu return; 101f28776a3SHerbert Xu } 102f28776a3SHerbert Xu 103f28776a3SHerbert Xu cipher->cia_decrypt(tfm, dst, src); 104f28776a3SHerbert Xu } 105f28776a3SHerbert Xu 1061da177e4SLinus Torvalds int crypto_init_cipher_ops(struct crypto_tfm *tfm) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds struct cipher_tfm *ops = &tfm->crt_cipher; 109f28776a3SHerbert Xu struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds ops->cit_setkey = setkey; 112f28776a3SHerbert Xu ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ? 113f28776a3SHerbert Xu cipher_encrypt_unaligned : cipher->cia_encrypt; 114f28776a3SHerbert Xu ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? 115f28776a3SHerbert Xu cipher_decrypt_unaligned : cipher->cia_decrypt; 1161da177e4SLinus Torvalds 117f1ddcaf3SHerbert Xu return 0; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds void crypto_exit_cipher_ops(struct crypto_tfm *tfm) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds } 123