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; }