Dr. Stephen Henson wrote:

>On Fri, Sep 10, 2004, Dr. Stephen Henson wrote:
>
>  
>
>>On Fri, Sep 10, 2004, Steve Hay wrote:
>>
>>    
>>
>>>As an alternative to my luckless attempts at using 
>>>EVP_CIPHER_param_to_asn1() + PKCS5_v2_PBE_keyivgen(), I thought I would 
>>>try PKCS5_pbe2_set() + EVP_PBE_CipherInit(), but I've run into the 
>>>problem that I thought I would have:  PKCS5_pbe2_set() randomly 
>>>generates its own IV, so that trying to decrypt previously encrypted 
>>>data doesn't work.  (Or at least, I think that's what the problem is.)
>>>
>>>I thought that calling
>>>
>>>    EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, crypt_mode);
>>>
>>>after the EVP_PBE_CipherInit() call would replace the iv set by 
>>>PKCS5_pbe2_set() with my own one, but it seems to make no difference, as 
>>>the attached sample program demonstrates.
>>>
>>>      
>>>
>>Currently you can't set the IV yourself in PKCS5_pbe2_set(). If you however
>>just want to save and restore the random IV (along with the parameters used
>>for the key) you can use the {i2d,d2i}_ASN1_TYPE() functions to save and
>>restore this to and from a memory buffer along with the salt and key length.
>>
>>    
>>
>
>Actually you'd be better just encoding and decoding the X509_ALGOR structure
>(pbe2 I believe you called it) before the data and on the decode side passing
>*that* to EVP_PBE_CipherInit().
>
OK, I tried that and it works very well.

However, as the attached program shows, it now turns out that this has 
all been a waste of time.  If you recall what my original problem was 
(namely, EVP_BytesToKey() only supports default key length -- see 
http://www.mail-archive.com/[EMAIL PROTECTED]/msg37111.html), 
the main reason for switching to EVP_PBE_CipherInit() was that 
PKCS5_v2_PBE_keyivgen(), which is called by EVP_PBE_CipherInit(), 
supposedly works with non-default key lengths.  But now that I've 
finally got it working I find that it doesn't support non-default key 
lengths after all.

Walking through the attached program in a debugger, I see that my 
EVP_CIPHER_CTX_set_key_length() call correctly sets the key length to 24 
(whereas BF default is 16), but then PKCS5_v2_PBE_keyivgen() does this:

    /* Fixup cipher based on AlgorithmIdentifier */
    EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de);

(crypto/evp/p5_crpt2.c line 185-6 in openssl-0.9.7d), which has the 
effect of resetting the key length in the ctx to the cipher's default, 
namely 16 here!

So now I'm back to square one: How do I do PKCS#5 key derivation using a 
non-default key length?

- Steve


------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are 
confidential and intended for the addressee(s) only.  If you have received this 
message in error or there are any problems, please notify the sender immediately.  The 
unauthorized use, disclosure, copying or alteration of this message is strictly 
forbidden.  Note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of Radan Computational Ltd.  The 
recipient(s) of this message should check it and any attached files for viruses: Radan 
Computational will accept no liability for any damage caused by any virus transmitted 
by this email.
#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
int main(int argc, char **argv) {
    FILE *in, *out;
    if (argc != 4) {
        printf("Usage: %s infile outfile cryptmode\n", argv[0]);
        return 2;
    }
    if ((in = fopen(argv[1], "rb")) == NULL) {
        printf("Error reading input\n");
        return 3;
    }
    if ((out = fopen(argv[2], "wb")) == NULL) {
        printf("Error writing output\n");
        return 4;
    }
    if (do_crypt(in, out, atoi(argv[3])) == 0) {
        printf("Error running do_crypt()\n");
        return 5;
    }
    return 0;
}
#define KEYLEN 24
const unsigned char pswd[] = "0123456789ABCDEFGHIJKLMN";
int do_crypt(FILE *in, FILE *out, int crypt_mode) {
    unsigned char inbuf[BUFSIZ], outbuf[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
    int inlen, outlen;
    unsigned char salt[PKCS5_SALT_LEN];
    const EVP_CIPHER *cipher = EVP_bf_cbc();
    X509_ALGOR *pbe2;
    EVP_CIPHER_CTX ctx;
    int len;
    unsigned char *buf, *p;
    char lenstr[10];
    if (crypt_mode) {
        if (!RAND_bytes(salt, PKCS5_SALT_LEN))
            return 0;
        pbe2 = PKCS5_pbe2_set(cipher, PKCS5_DEFAULT_ITER, salt, PKCS5_SALT_LEN);
        len = i2d_X509_ALGOR(pbe2, NULL);
        buf = OPENSSL_malloc(len);
        p = buf;
        i2d_X509_ALGOR(pbe2, &p);
        itoa(len, lenstr, 10);
        fwrite(lenstr, 1, strlen(lenstr) + 1, out); // Include '\0' in output
        fwrite(buf, 1, len, out);
        OPENSSL_free(buf);
    }
    else {
        fscanf(in, "%10[^\0]%*[\0]", lenstr);
        len = atoi(lenstr);
        buf = OPENSSL_malloc(len);
        fread(buf, 1, len, in);
        p = buf;
        pbe2 = NULL;
        d2i_X509_ALGOR(&pbe2, &p, len);
        OPENSSL_free(buf);
    }
    EVP_add_cipher(cipher);
    PKCS5_PBE_add();
    EVP_CIPHER_CTX_init(&ctx);
    EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, crypt_mode);
    EVP_CIPHER_CTX_set_key_length(&ctx, KEYLEN);
    if (!EVP_PBE_CipherInit(pbe2->algorithm, pswd, KEYLEN, pbe2->parameter,
            &ctx, crypt_mode))
        return 0;
    printf("Key length: %d\n", EVP_CIPHER_CTX_key_length(&ctx));
    for (;;) {
        if ((inlen = fread(inbuf, 1, BUFSIZ, in)) < 0)
            return 0;
        else if (inlen == 0)
            break;
        if (!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
            return 0;
        fwrite(outbuf, 1, outlen, out);
    }
    if (!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
        return 0;
    fwrite(outbuf, 1, outlen, out);
    EVP_CIPHER_CTX_cleanup(&ctx);
    EVP_cleanup();
    return 1;
}

Reply via email to