My previous mail doesn't seem to have appeared on the list, so sending
again:


Hello,

As the maintainer of a package which uses OpenSSL, I've received some
reports
of 0.9.8e failing to decrypt data which was encrypted by previous versions
of
OpenSSL.

Attached is a small bit of C++ code which demonstrates the problem.  It uses

the EVP interface with EVP_bf_cfb as the cipher and a 256 bit key (the
reports all point to Blowfish with key length > 128 bits).  What it does is
set a key, an IV, and run an encryption pass, then a decryption and compute
checksums of the three arrays (original, encrypted, decrypted).

When built against 0.9.8c, I get:
ort:tmp> g++ -Wall -g -o ssltest ssltest.cpp -lssl -lcrypto -lz
ort:tmp> ./ssltest
src chksum = 698614540
stage2 chksum = 2266501868
final chksum = 698614540

Another machine with 0.9.7a gives an identical result.  On a machine I
upgraded to 0.9.8e, I get the following output:

src chksum = 698614540
stage2 chksum = 2108297998
final chksum = 698614540


"stage2" is the encrypted data, and it differs on 0.9.8e.  What this means
in
practice is that the program I'm using can encrypt/decrypt data just fine
when run in either version of OpenSSL, but if data is encrypted in an
earlier
version and then OpenSSL is upgraded to 0.9.8e, then decryption fails.

The nearest I've narrowed down is to something changing between 0.9.8c and
0.9.8e, but I've received reports that 0.9.8d -> 0.9.8e also fails.  I've
been looking at the diffs between 0.9.8d -> 0.9.8e, but I'm not seeing any
obvious problem.  Reports are that only Blowfish with key > 128 bits has a
problem, and AES users are not affected.

Any ideas what's wrong, and if there's a way to get 0.9.8e output to match
earlier versions?

regards,
Valient
/*
    Build using:

    g++ -g -o ssltest ssltest.cpp -lssl -lcrypto -lz

*/

#include <openssl/evp.h>
#include <zlib.h>
#include <assert.h>
#include <string.h>


int main()
{
    const int keySize = 32; // 256 bit key
    unsigned char keyBytes[keySize];

    const EVP_CIPHER *cipher = EVP_bf_cfb();
    EVP_CIPHER_CTX stream_enc;
    EVP_CIPHER_CTX stream_dec;

    // init key to known value
    for(int i=0; i<keySize; ++i)
        keyBytes[i] = (unsigned char)i;

    // setup IV
    int ivLen = EVP_CIPHER_iv_length( cipher );
    assert(ivLen == 8);

    unsigned char ivec[8];
    for(int i=0; i<8; ++i)
        ivec[i] = (unsigned char)i;

    // setup cipher and a context for encryption and decryption
    EVP_CIPHER_CTX_init( &stream_enc );
    EVP_CIPHER_CTX_init( &stream_dec );

    EVP_EncryptInit_ex( &stream_enc, cipher, NULL, NULL, NULL );
    EVP_DecryptInit_ex( &stream_dec, cipher, NULL, NULL, NULL );

    EVP_CIPHER_CTX_set_key_length( &stream_enc, keySize );
    EVP_CIPHER_CTX_set_key_length( &stream_dec, keySize );

    EVP_CIPHER_CTX_set_padding( &stream_enc, 0 );
    EVP_CIPHER_CTX_set_padding( &stream_dec, 0 );

    // initialize key
    EVP_EncryptInit_ex( &stream_enc, NULL, NULL, keyBytes, NULL );
    EVP_DecryptInit_ex( &stream_dec, NULL, NULL, keyBytes, NULL );

    // Encode src -> stage2, then decode state2 -> final
    const int size = 40;
    unsigned char src[size];
    unsigned char stage2[size];
    unsigned char final[size];

    for(int i=0; i<size; ++i)
        src[i] = (unsigned char)i;
    memset(stage2, 0, sizeof(stage2));
    memset(final, 0, sizeof(final));

    int dstLen;
    int tmpLen;
    
    uLong chksum1 = adler32(0L, src, size);
    printf("src chksum = %lu\n", chksum1);

    /* encrypt some data */
    EVP_EncryptInit_ex( &stream_enc, NULL, NULL, NULL, ivec );
    EVP_EncryptUpdate( &stream_enc, stage2, &dstLen, src, size );
    EVP_EncryptFinal_ex( &stream_enc, stage2+dstLen, &tmpLen );
    assert(dstLen == size);
    assert(tmpLen == 0);

    uLong chksum2 = adler32(0L, stage2, size);
    printf("stage2 chksum = %lu\n", chksum2);

    /* decrypt */
    EVP_DecryptInit_ex( &stream_dec, NULL, NULL, NULL, ivec );
    EVP_DecryptUpdate( &stream_dec, final, &dstLen, stage2, size );
    EVP_DecryptFinal_ex( &stream_dec, final+dstLen, &tmpLen );
    assert(dstLen == size);
    assert(tmpLen == 0);
    
    uLong chksum3 = adler32(0L, final, size);
    printf("final chksum = %lu\n", chksum3);

    /* compare */
    int res = memcmp(src, final, size);
    assert(res == 0);

    return res;
}

Reply via email to