Bug:
  Decrypting *cfb1 encrypted data via BIO_read() leads to corruption
OpenSSL versions impacted: 
  I have reproduced this issue in 0.9.8 and 1.0.0 (beta)
OS tested:
  RHEL Linux 5.0

Below is a program demonstrating that decrypting data encrypted by *cfb1 
algorithms can lead to corruption of the decrypted data (if its length
is more than EVP_MAX_BLOCK_LENGTH*2 (64 bytes). The issue does not seem
to happen with "des-cfb1" (since that one is not using the underlying
CRYPTO_cfb128_1_encrypt() function that seems to be the culprit).

I guess this is due to the overlapping buffers mentioned in this fix:
http://cvs.openssl.org/filediff?f=openssl/crypto/evp/bio_enc.c&v1=1.17&v2=1.18

However due the nature of this issue I do not think increasing BUF_OFFSET
further would help -  since the function in question (CRYPTO_cfb128_1_encrypt())
might corrupt the decrypted data as its size increases in relation to 
BUF_OFFSET.

The problem seems to have been introduced with this checkin:
http://cvs.openssl.org/filediff?f=openssl/crypto/aes/aes_cfb.c&v1=1.3&v2=1.4

I think the solution to this is to remove the line that clears the "out"
memory buffer before running the decryption loop (I do not think it is 
really needed, at least the "equivalent" function in e_des.c does not have it), 
i.e. (diff against cfb128.c in HEAD (and 1.0.0) branch):

*** cfb128.c    29 Dec 2008 12:35:48 -0000      1.3
--- cfb128.c    6 Feb 2010 06:58:19 -0000
***************
*** 224,230 ****
      assert(in && out && key && ivec && num);
      assert(*num == 0);

-     memset(out,0,(bits+7)/8);
      for(n=0 ; n<bits ; ++n)
        {
        c[0]=(in[n/8]&(1 << (7-n%8))) ? 0x80 : 0;


István Noszticzius

-----------------------------------------------------------------------------

//
// DEMO of *cfb1 decryption corruption 
//

#include <stdio.h>

#include <openssl/evp.h>
#include <openssl/bio.h>

static void hexdump(char* header, unsigned char *data, int data_len)
{
    int i;
    printf("%s (%d):\n", header, data_len);
    for(i = 0; i < data_len; i++) {
        printf("%02X%s", data[i], i < data_len-1 ? " " : "");
        if (!((i+1) % 16) || i == data_len-1)
            printf("\n");
    }
}

int main(int argc, char** argv)
{
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    const EVP_CIPHER *cipher=
        EVP_get_cipherbyname("aes-128-cfb1");

    //
    // This data Can be generated by:
    // echo 
"123456789012345678901234567890123456789012345678901234567890123456" |\
    // openssl enc -e -aes-128-cfb1 -K 3132333435363738 -iv 3132333435363738 |\
    unsigned char input_data[] =
        "\x25\x39\x7a\x36\xc9\x23\xc5\xc9"
        "\x26\xa3\x17\x7f\x28\xdb\xae\x3f"
        "\x6b\x1c\x82\xa3\x59\xc1\x09\x7a"
        "\x3d\xed\xe6\xb4\x4b\xf9\xb9\xa9"
        "\xe3\xa9\xc5\x1f\xbe\xa5\x03\xf3"
        "\x6a\x34\xa8\x05\x2e\x7f\xc5\x91"
        "\x35\x22\xe8\x8c\x64\x77\x77\xbe"
        "\x7c\x3b\x93\xdf\x7d\x81\x54\x57"
        "\xd5\xeb\x1a";

    unsigned char key[16] =
        "\x31\x32\x33\x34\x35\x36\x37\x38"
        "\x00\x00\x00\x00\x00\x00\x00\x00";

    unsigned char iv[16]  =
        "\x31\x32\x33\x34\x35\x36\x37\x38"
        "\x00\x00\x00\x00\x00\x00\x00\x00";

    BIO *input_bio =
        // -1 to cut off trailing 0
        BIO_new_mem_buf(input_data, sizeof(input_data)-1);
    BIO *output_bio = BIO_new(BIO_s_mem());
    BIO *decryption_bio = BIO_new(BIO_f_cipher());
    BIO_set_cipher(decryption_bio, cipher, key, iv, 0);

#if 1
    //
    // Decrypting data while reading: Does not work
    // (i.e. results in corruption)
    input_bio = BIO_push(decryption_bio, input_bio);
#else
    //
    // Decrypting data while writing: Works
    //
    output_bio = BIO_push(decryption_bio, output_bio);
#endif

    unsigned char tmpbuff[256];
    for (;;)
    {
        int inl = BIO_read(input_bio, tmpbuff, sizeof(tmpbuff));
        if (inl <= 0) break;
        BIO_write(output_bio, tmpbuff, inl);
    }

    unsigned char* output_data;
    int outl = BIO_get_mem_data(output_bio, &output_data);
    hexdump("Decrypted Data", output_data, outl);

    return(0);
}

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to