From 94f701a826b54e6652044bdba9a8b6a9aa2b479e Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Thu, 26 Feb 2015 22:04:40 +0100
Subject: [PATCH 337/506] crypto: restrict cipher block size to power of 2.
All current ciphers have blocks which are power of 2 and it's
unlikely to change. Other block length would be tricky to handle anyway.
This restriction allows avoiding extra divisions.
---
grub-core/disk/cryptodisk.c | 36 +++++++++++++++++++++---------------
grub-core/lib/crypto.c | 42 +++++++++++++++++++++++++++---------------
2 files changed, 48 insertions(+), 30 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 376ab83..82a3dcb 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -110,20 +110,23 @@ grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher,
{
grub_uint8_t *inptr, *outptr, *end;
grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
- if (cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
- return GPG_ERR_INV_ARG;
+ grub_size_t blocksize;
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
+ return GPG_ERR_INV_ARG;
+ if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
{
- grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
+ grub_memcpy (ivt, inptr, blocksize);
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
- grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
- grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize);
+ grub_crypto_xor (outptr, outptr, iv, blocksize);
+ grub_crypto_xor (iv, ivt, outptr, blocksize);
}
return GPG_ERR_NO_ERROR;
}
@@ -135,20 +138,23 @@ grub_crypto_pcbc_encrypt (grub_crypto_cipher_handle_t cipher,
{
grub_uint8_t *inptr, *outptr, *end;
grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
- if (cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
- return GPG_ERR_INV_ARG;
- if (!cipher->cipher->decrypt)
+ grub_size_t blocksize;
+ if (!cipher->cipher->encrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
+ return GPG_ERR_INV_ARG;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
return GPG_ERR_INV_ARG;
end = (grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
{
- grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
- grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
+ grub_memcpy (ivt, inptr, blocksize);
+ grub_crypto_xor (outptr, outptr, iv, blocksize);
cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
- grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize);
+ grub_crypto_xor (iv, ivt, outptr, blocksize);
}
return GPG_ERR_NO_ERROR;
}
diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
index 8e8426c..010e550 100644
--- a/grub-core/lib/crypto.c
+++ b/grub-core/lib/crypto.c
@@ -205,13 +205,16 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
{
const grub_uint8_t *inptr, *end;
grub_uint8_t *outptr;
+ grub_size_t blocksize;
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
return GPG_ERR_INV_ARG;
end = (const grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
return GPG_ERR_NO_ERROR;
}
@@ -222,13 +225,16 @@ grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
{
const grub_uint8_t *inptr, *end;
grub_uint8_t *outptr;
+ grub_size_t blocksize;
if (!cipher->cipher->encrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
return GPG_ERR_INV_ARG;
end = (const grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
return GPG_ERR_NO_ERROR;
}
@@ -241,20 +247,23 @@ grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
grub_uint8_t *outptr;
const grub_uint8_t *inptr, *end;
void *iv;
- if (!cipher->cipher->decrypt)
+ grub_size_t blocksize;
+ if (!cipher->cipher->encrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
return GPG_ERR_INV_ARG;
end = (const grub_uint8_t *) in + size;
iv = iv_in;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
{
- grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize);
+ grub_crypto_xor (outptr, inptr, iv, blocksize);
cipher->cipher->encrypt (cipher->ctx, outptr, outptr);
iv = outptr;
}
- grub_memcpy (iv_in, iv, cipher->cipher->blocksize);
+ grub_memcpy (iv_in, iv, blocksize);
return GPG_ERR_NO_ERROR;
}
@@ -266,20 +275,23 @@ grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
const grub_uint8_t *inptr, *end;
grub_uint8_t *outptr;
grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
+ grub_size_t blocksize;
if (!cipher->cipher->decrypt)
return GPG_ERR_NOT_SUPPORTED;
- if (size % cipher->cipher->blocksize != 0)
+ blocksize = cipher->cipher->blocksize;
+ if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
+ || ((size & (blocksize - 1)) != 0))
return GPG_ERR_INV_ARG;
- if (cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
+ if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
return GPG_ERR_INV_ARG;
end = (const grub_uint8_t *) in + size;
for (inptr = in, outptr = out; inptr < end;
- inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
+ inptr += blocksize, outptr += blocksize)
{
- grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
+ grub_memcpy (ivt, inptr, blocksize);
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
- grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
- grub_memcpy (iv, ivt, cipher->cipher->blocksize);
+ grub_crypto_xor (outptr, outptr, iv, blocksize);
+ grub_memcpy (iv, ivt, blocksize);
}
return GPG_ERR_NO_ERROR;
}
--
2.4.3