From 94f701a826b54e6652044bdba9a8b6a9aa2b479e Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko 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