This is the main PKCS#5 v2.0 key generation function, it parses the ASN1
authorDr. Stephen Henson <steve@openssl.org>
Mon, 7 Jun 1999 21:00:19 +0000 (21:00 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Mon, 7 Jun 1999 21:00:19 +0000 (21:00 +0000)
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
crypto/asn1/p5_pbev2.c
crypto/evp/Makefile.ssl
crypto/evp/evp.h
crypto/evp/evp_err.c
crypto/evp/p5_crpt.c
crypto/evp/p5_crpt2.c [new file with mode: 0644]
crypto/hmac/hmac.c
crypto/hmac/hmac.h
crypto/pkcs12/p12_crpt.c

index 900291f..16755a0 100644 (file)
@@ -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"},
index 6400c10..51e587e 100644 (file)
@@ -270,4 +270,3 @@ X509_ALGOR *PKCS5_pbe2_set(EVP_CIPHER *cipher, int iter, unsigned char *salt,
        return NULL;
 
 }
-
index 4b762dd..4afa72f 100644 (file)
@@ -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)
 
index 417e049..b38ea6e 100644 (file)
@@ -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
 
index cd00af8..c61cc92 100644 (file)
@@ -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}
index 2d80c34..0cf7e9d 100644 (file)
@@ -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 (file)
index 0000000..78fd0ef
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <openssl/x509.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#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
+ * <pgut001@cs.auckland.ac.nz> to the PKCS-TNG <pkcs-tng@rsa.com> 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;
+}
+
index d31e880..0825536 100644 (file)
@@ -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;
index 00f9d72..5720498 100644 (file)
@@ -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);
 
 
index ae516ee..d942654 100644 (file)
@@ -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;
        }