summaryrefslogtreecommitdiffstats
path: root/crypto/cipher.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-08-13 20:58:18 +1000
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-21 11:41:51 +1000
commitf28776a369b12f9a03a822a8e1090ed670a41f4f (patch)
treeb1eb08db2d7ad5c83a4b2784aea3af0502d127b3 /crypto/cipher.c
parente853c3cfa8cc24869ecd2526e589bcb176bc12e9 (diff)
downloadlinux-f28776a369b12f9a03a822a8e1090ed670a41f4f.tar.bz2
[CRYPTO] cipher: Added encrypt_one/decrypt_one
This patch adds two new operations for the simple cipher that encrypts or decrypts a single block at a time. This will be the main interface after the existing block operations have moved over to the new block ciphers. It also adds the crypto_cipher type which is currently only used on the new operations but will be extended to setkey as well once existing users have been converted to use block ciphers where applicable. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/cipher.c')
-rw-r--r--crypto/cipher.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/crypto/cipher.c b/crypto/cipher.c
index f573c59ed9dc..d8ca0ec8d0be 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -388,12 +388,60 @@ int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
return 0;
}
+static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
+ const u8 *),
+ struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ unsigned int size = crypto_tfm_alg_blocksize(tfm);
+ u8 buffer[size + alignmask];
+ u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+
+ memcpy(tmp, src, size);
+ fn(tfm, tmp, tmp);
+ memcpy(dst, tmp, size);
+}
+
+static void cipher_encrypt_unaligned(struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+ cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src);
+ return;
+ }
+
+ cipher->cia_encrypt(tfm, dst, src);
+}
+
+static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+ cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src);
+ return;
+ }
+
+ cipher->cia_decrypt(tfm, dst, src);
+}
+
int crypto_init_cipher_ops(struct crypto_tfm *tfm)
{
int ret = 0;
struct cipher_tfm *ops = &tfm->crt_cipher;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
ops->cit_setkey = setkey;
+ ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+ cipher_encrypt_unaligned : cipher->cia_encrypt;
+ ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+ cipher_decrypt_unaligned : cipher->cia_decrypt;
switch (tfm->crt_cipher.cit_mode) {
case CRYPTO_TFM_MODE_ECB: