From 97e4a932451188508b6f865b1a16f2e670a1c315 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 7 Jun 1999 21:00:19 +0000 Subject: [PATCH] This is the main PKCS#5 v2.0 key generation function, it parses the ASN1 structure and decides what key to generate (if any). Not currently added to the PBE algorithm list because it is largely untested. --- crypto/asn1/asn1_err.c | 2 +- crypto/asn1/p5_pbev2.c | 1 - crypto/evp/Makefile.ssl | 4 +- crypto/evp/evp.h | 14 ++- crypto/evp/evp_err.c | 8 +- crypto/evp/p5_crpt.c | 6 +- crypto/evp/p5_crpt2.c | 221 +++++++++++++++++++++++++++++++++++++++ crypto/hmac/hmac.c | 2 +- crypto/hmac/hmac.h | 2 +- crypto/pkcs12/p12_crpt.c | 4 +- 10 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 crypto/evp/p5_crpt2.c diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 900291fb6a..16755a0b05 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -209,7 +209,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_PACK(0,ASN1_F_PKCS12_MAC_DATA_NEW,0), "PKCS12_MAC_DATA_new"}, {ERR_PACK(0,ASN1_F_PKCS12_NEW,0), "PKCS12_new"}, {ERR_PACK(0,ASN1_F_PKCS12_SAFEBAG_NEW,0), "PKCS12_SAFEBAG_new"}, -{ERR_PACK(0,ASN1_F_PKCS5_PBE2_SET,0), "PKCS5_PBE2_SET"}, +{ERR_PACK(0,ASN1_F_PKCS5_PBE2_SET,0), "PKCS5_pbe2_set"}, {ERR_PACK(0,ASN1_F_PKCS7_DIGEST_NEW,0), "PKCS7_DIGEST_new"}, {ERR_PACK(0,ASN1_F_PKCS7_ENCRYPT_NEW,0), "PKCS7_ENCRYPT_new"}, {ERR_PACK(0,ASN1_F_PKCS7_ENC_CONTENT_NEW,0), "PKCS7_ENC_CONTENT_new"}, diff --git a/crypto/asn1/p5_pbev2.c b/crypto/asn1/p5_pbev2.c index 6400c10364..51e587e923 100644 --- a/crypto/asn1/p5_pbev2.c +++ b/crypto/asn1/p5_pbev2.c @@ -270,4 +270,3 @@ X509_ALGOR *PKCS5_pbe2_set(EVP_CIPHER *cipher, int iter, unsigned char *salt, return NULL; } - diff --git a/crypto/evp/Makefile.ssl b/crypto/evp/Makefile.ssl index 4b762ddbf2..4afa72f315 100644 --- a/crypto/evp/Makefile.ssl +++ b/crypto/evp/Makefile.ssl @@ -35,7 +35,7 @@ LIBSRC= encode.c digest.c evp_enc.c evp_key.c \ m_ripemd.c \ p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c \ bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \ - c_all.c evp_lib.c bio_ok.c evp_pkey.c evp_pbe.c p5_crpt.c + c_all.c evp_lib.c bio_ok.c evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c LIBOBJ= encode.o digest.o evp_enc.o evp_key.o \ e_ecb_d.o e_cbc_d.o e_cfb_d.o e_ofb_d.o \ @@ -50,7 +50,7 @@ LIBOBJ= encode.o digest.o evp_enc.o evp_key.o \ m_ripemd.o \ p_open.o p_seal.o p_sign.o p_verify.o p_lib.o p_enc.o p_dec.o \ bio_md.o bio_b64.o bio_enc.o evp_err.o e_null.o \ - c_all.o evp_lib.o bio_ok.o evp_pkey.o evp_pbe.o p5_crpt.o + c_all.o evp_lib.o bio_ok.o evp_pkey.o evp_pbe.o p5_crpt.o p5_crpt2.o SRC= $(LIBSRC) diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 417e049620..b38ea6e999 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -640,6 +640,12 @@ int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type); int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, EVP_CIPHER *cipher, EVP_MD *md, int en_de); +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out); +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, EVP_CIPHER *cipher, EVP_MD *md, + int en_de); void PKCS5_PBE_add(void); @@ -663,7 +669,6 @@ void EVP_PBE_cleanup(void); #define EVP_F_EVP_OPENINIT 102 #define EVP_F_EVP_PBE_ALG_ADD 115 #define EVP_F_EVP_PBE_CIPHERINIT 116 -#define EVP_F_EVP_PKCS5_PBE_KEYIVGEN 117 #define EVP_F_EVP_PKCS82PKEY 111 #define EVP_F_EVP_PKCS8_SET_BROKEN 112 #define EVP_F_EVP_PKEY2PKCS8 113 @@ -673,12 +678,15 @@ void EVP_PBE_cleanup(void); #define EVP_F_EVP_PKEY_NEW 106 #define EVP_F_EVP_SIGNFINAL 107 #define EVP_F_EVP_VERIFYFINAL 108 +#define EVP_F_PKCS5_PBE_KEYIVGEN 117 +#define EVP_F_PKCS5_V2_PBE_KEYIVGEN 118 #define EVP_F_RC2_MAGIC_TO_METH 109 /* Reason codes. */ #define EVP_R_BAD_DECRYPT 100 #define EVP_R_BN_DECODE_ERROR 112 #define EVP_R_BN_PUBKEY_ERROR 113 +#define EVP_R_CIPHER_PARAMETER_ERROR 122 #define EVP_R_DECODE_ERROR 114 #define EVP_R_DIFFERENT_KEY_TYPES 101 #define EVP_R_ENCODE_ERROR 115 @@ -694,8 +702,12 @@ void EVP_PBE_cleanup(void); #define EVP_R_PUBLIC_KEY_NOT_RSA 106 #define EVP_R_UNKNOWN_PBE_ALGORITHM 121 #define EVP_R_UNSUPPORTED_CIPHER 107 +#define EVP_R_UNSUPPORTED_KEYLENGTH 123 +#define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 124 #define EVP_R_UNSUPPORTED_KEY_SIZE 108 +#define EVP_R_UNSUPPORTED_PRF 125 #define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 118 +#define EVP_R_UNSUPPORTED_SALT_TYPE 126 #define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109 #define EVP_R_WRONG_PUBLIC_KEY_TYPE 110 diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index cd00af8b77..c61cc922e8 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -71,7 +71,6 @@ static ERR_STRING_DATA EVP_str_functs[]= {ERR_PACK(0,EVP_F_EVP_OPENINIT,0), "EVP_OpenInit"}, {ERR_PACK(0,EVP_F_EVP_PBE_ALG_ADD,0), "EVP_PBE_alg_add"}, {ERR_PACK(0,EVP_F_EVP_PBE_CIPHERINIT,0), "EVP_PBE_CipherInit"}, -{ERR_PACK(0,EVP_F_EVP_PKCS5_PBE_KEYIVGEN,0), "EVP_PKCS5_PBE_KEYIVGEN"}, {ERR_PACK(0,EVP_F_EVP_PKCS82PKEY,0), "EVP_PKCS82PKEY"}, {ERR_PACK(0,EVP_F_EVP_PKCS8_SET_BROKEN,0), "EVP_PKCS8_SET_BROKEN"}, {ERR_PACK(0,EVP_F_EVP_PKEY2PKCS8,0), "EVP_PKEY2PKCS8"}, @@ -81,6 +80,8 @@ static ERR_STRING_DATA EVP_str_functs[]= {ERR_PACK(0,EVP_F_EVP_PKEY_NEW,0), "EVP_PKEY_new"}, {ERR_PACK(0,EVP_F_EVP_SIGNFINAL,0), "EVP_SignFinal"}, {ERR_PACK(0,EVP_F_EVP_VERIFYFINAL,0), "EVP_VerifyFinal"}, +{ERR_PACK(0,EVP_F_PKCS5_PBE_KEYIVGEN,0), "PKCS5_PBE_keyivgen"}, +{ERR_PACK(0,EVP_F_PKCS5_V2_PBE_KEYIVGEN,0), "PKCS5_v2_PBE_keyivgen"}, {ERR_PACK(0,EVP_F_RC2_MAGIC_TO_METH,0), "RC2_MAGIC_TO_METH"}, {0,NULL} }; @@ -90,6 +91,7 @@ static ERR_STRING_DATA EVP_str_reasons[]= {EVP_R_BAD_DECRYPT ,"bad decrypt"}, {EVP_R_BN_DECODE_ERROR ,"bn decode error"}, {EVP_R_BN_PUBKEY_ERROR ,"bn pubkey error"}, +{EVP_R_CIPHER_PARAMETER_ERROR ,"cipher parameter error"}, {EVP_R_DECODE_ERROR ,"decode error"}, {EVP_R_DIFFERENT_KEY_TYPES ,"different key types"}, {EVP_R_ENCODE_ERROR ,"encode error"}, @@ -105,8 +107,12 @@ static ERR_STRING_DATA EVP_str_reasons[]= {EVP_R_PUBLIC_KEY_NOT_RSA ,"public key not rsa"}, {EVP_R_UNKNOWN_PBE_ALGORITHM ,"unknown pbe algorithm"}, {EVP_R_UNSUPPORTED_CIPHER ,"unsupported cipher"}, +{EVP_R_UNSUPPORTED_KEYLENGTH ,"unsupported keylength"}, +{EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION,"unsupported key derivation function"}, {EVP_R_UNSUPPORTED_KEY_SIZE ,"unsupported key size"}, +{EVP_R_UNSUPPORTED_PRF ,"unsupported prf"}, {EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM ,"unsupported private key algorithm"}, +{EVP_R_UNSUPPORTED_SALT_TYPE ,"unsupported salt type"}, {EVP_R_WRONG_FINAL_BLOCK_LENGTH ,"wrong final block length"}, {EVP_R_WRONG_PUBLIC_KEY_TYPE ,"wrong public key type"}, {0,NULL} diff --git a/crypto/evp/p5_crpt.c b/crypto/evp/p5_crpt.c index 2d80c3416a..0cf7e9d45e 100644 --- a/crypto/evp/p5_crpt.c +++ b/crypto/evp/p5_crpt.c @@ -99,9 +99,9 @@ int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen, /* Extract useful info from parameter */ pbuf = param->value.sequence->data; - if (!(pbe = d2i_PBEPARAM (NULL, &pbuf, - param->value.sequence->length))) { - EVPerr(EVP_F_EVP_PKCS5_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); + if (!param || (param->type = V_ASN1_SEQUENCE) || + !(pbe = d2i_PBEPARAM (NULL, &pbuf, param->value.sequence->length))) { + EVPerr(EVP_F_PKCS5_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); return 0; } diff --git a/crypto/evp/p5_crpt2.c b/crypto/evp/p5_crpt2.c new file mode 100644 index 0000000000..78fd0ef14d --- /dev/null +++ b/crypto/evp/p5_crpt2.c @@ -0,0 +1,221 @@ +/* p5_crpt2.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include +#include +#include +#include +#include +#include "cryptlib.h" + +/* This is an implementation of PKCS#5 v2.0 password based encryption key + * derivation function PBKDF2 using the only currently defined function HMAC + * with SHA1. Verified against test vectors posted by Peter Gutmann + * to the PKCS-TNG mailing list. + */ + +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out) +{ + unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4]; + int cplen, j, k; + unsigned long i = 1; + HMAC_CTX hctx; + p = out; + if(passlen == -1) passlen = strlen(pass); + while(keylen) { + if(keylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH; + else cplen = keylen; + /* We are unlikely to ever use more than 256 blocks (5120 bits!) + * but just in case... + */ + itmp[0] = (i >> 24) & 0xff; + itmp[1] = (i >> 16) & 0xff; + itmp[2] = (i >> 8) & 0xff; + itmp[3] = i & 0xff; + HMAC_Init(&hctx, pass, passlen, EVP_sha1()); + HMAC_Update(&hctx, salt, saltlen); + HMAC_Update(&hctx, itmp, 4); + HMAC_Final(&hctx, digtmp, NULL); + memcpy(p, digtmp, cplen); + for(j = 1; j < iter; j++) { + HMAC(EVP_sha1(), pass, passlen, + digtmp, SHA_DIGEST_LENGTH, digtmp, NULL); + for(k = 0; k < cplen; k++) p[k] ^= digtmp[k]; + } + keylen-= cplen; + i++; + p+= cplen; + } + HMAC_cleanup(&hctx); + return 1; +} + +#ifdef DO_TEST +main() +{ + unsigned char out[4]; + unsigned char salt[] = {0x12, 0x34, 0x56, 0x78}; + PKCS5_PBKDF2_HMAC_SHA1("password", -1, salt, 4, 5, 4, out); + fprintf(stderr, "Out %02X %02X %02X %02X\n", + out[0], out[1], out[2], out[3]); +} + +#endif + +/* Now the key derivation function itself. This is a bit evil because + * it has to check the ASN1 parameters are valid: and there are quite a + * few of them... + */ + +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, EVP_CIPHER *c, EVP_MD *md, + int en_de) +{ + unsigned char *pbuf, *salt, key[EVP_MAX_KEY_LENGTH]; + int saltlen, keylen, iter, plen; + PBE2PARAM *pbe2 = NULL; + const EVP_CIPHER *cipher; + PBKDF2PARAM *kdf = NULL; + + pbuf = param->value.sequence->data; + plen = param->value.sequence->length; + if(!param || (param->type != V_ASN1_SEQUENCE) || + !(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); + return 0; + } + + /* See if we recognise the key derivation function */ + + if(OBJ_obj2nid(pbe2->keyfunc->algorithm) != NID_id_pbkdf2) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION); + goto err; + } + + /* lets see if we recognise the encryption algorithm. + */ + + cipher = EVP_get_cipherbyname( + OBJ_nid2sn(OBJ_obj2nid(pbe2->encryption->algorithm))); + + if(!cipher) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVP_R_UNSUPPORTED_CIPHER); + goto err; + } + + /* Fixup cipher based on AlgorithmIdentifier */ + EVP_CipherInit(ctx, cipher, NULL, NULL, en_de); + if(EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVP_R_CIPHER_PARAMETER_ERROR); + goto err; + } + keylen = EVP_CIPHER_CTX_key_length(ctx); + + /* Now decode key derivation function */ + + pbuf = pbe2->keyfunc->parameter->value.sequence->data; + plen = pbe2->keyfunc->parameter->value.sequence->length; + if(!pbe2->keyfunc->parameter || + (pbe2->keyfunc->parameter->type != V_ASN1_SEQUENCE) || + !(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen)) ) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); + goto err; + } + + PBE2PARAM_free(pbe2); + pbe2 = NULL; + + /* Now check the parameters of the kdf */ + + if(kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != keylen)){ + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVP_R_UNSUPPORTED_KEYLENGTH); + goto err; + } + + if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); + goto err; + } + + if(kdf->salt->type != V_ASN1_OCTET_STRING) { + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, + EVP_R_UNSUPPORTED_SALT_TYPE); + goto err; + } + + /* it seems that its all OK */ + salt = kdf->salt->value.octet_string->data; + saltlen = kdf->salt->value.octet_string->length; + iter = ASN1_INTEGER_get(kdf->iter); + PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen, iter, keylen, key); + EVP_CipherInit(ctx, NULL, key, NULL, en_de); + memset(key, 0, keylen); + PBKDF2PARAM_free(kdf); + return 1; + + err: + PBE2PARAM_free(pbe2); + PBKDF2PARAM_free(kdf); + return 0; +} + diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c index d31e880e6f..0825536393 100644 --- a/crypto/hmac/hmac.c +++ b/crypto/hmac/hmac.c @@ -133,7 +133,7 @@ void HMAC_cleanup(HMAC_CTX *ctx) memset(ctx,0,sizeof(HMAC_CTX)); } -unsigned char *HMAC(EVP_MD *evp_md, unsigned char *key, int key_len, +unsigned char *HMAC(const EVP_MD *evp_md, const unsigned char *key, int key_len, unsigned char *d, int n, unsigned char *md, unsigned int *md_len) { HMAC_CTX c; diff --git a/crypto/hmac/hmac.h b/crypto/hmac/hmac.h index 00f9d7203c..57204985d3 100644 --- a/crypto/hmac/hmac.h +++ b/crypto/hmac/hmac.h @@ -88,7 +88,7 @@ void HMAC_Init(HMAC_CTX *ctx, const unsigned char *key, int len, void HMAC_Update(HMAC_CTX *ctx,unsigned char *key, int len); void HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); void HMAC_cleanup(HMAC_CTX *ctx); -unsigned char *HMAC(EVP_MD *evp_md, unsigned char *key, int key_len, +unsigned char *HMAC(const EVP_MD *evp_md, const unsigned char *key, int key_len, unsigned char *d, int n, unsigned char *md, unsigned int *md_len); diff --git a/crypto/pkcs12/p12_crpt.c b/crypto/pkcs12/p12_crpt.c index ae516eeb8d..d94265403a 100644 --- a/crypto/pkcs12/p12_crpt.c +++ b/crypto/pkcs12/p12_crpt.c @@ -92,8 +92,8 @@ int PKCS12_PBE_keyivgen (EVP_CIPHER_CTX *ctx, const char *pass, int passlen, /* Extract useful info from parameter */ pbuf = param->value.sequence->data; - if (!(pbe = d2i_PBEPARAM (NULL, &pbuf, - param->value.sequence->length))) { + if (!param || (param->type = V_ASN1_SEQUENCE) || + !(pbe = d2i_PBEPARAM (NULL, &pbuf, param->value.sequence->length))) { EVPerr(PKCS12_F_PKCS12_PBE_KEYIVGEN,EVP_R_DECODE_ERROR); return 0; } -- 2.25.1