Extend PBE code to support non default PKCS#5 v2.0 PRFs.

This commit is contained in:
Dr. Stephen Henson 2006-05-14 18:40:53 +00:00
parent 76240b3a39
commit 856640b54f
9 changed files with 190 additions and 65 deletions

View file

@ -4,6 +4,9 @@
Changes between 0.9.8b and 0.9.9 [xx XXX xxxx]
*) Initial support for PKCS#5 v2.0 PRFs other than default SHA1 HMAC.
[Steve Henson]
*) Replace the algorithm specific calls to generate keys in "req" with the
new API.
[Steve Henson]

View file

@ -799,8 +799,20 @@ void PKCS5_PBE_add(void);
int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de);
/* PBE type */
/* Can appear as the outermost AlgorithmIdentifier */
#define EVP_PBE_TYPE_OUTER 0x0
/* Is an PRF type OID */
#define EVP_PBE_TYPE_PRF 0x1
int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, int md_nid,
EVP_PBE_KEYGEN *keygen);
int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
EVP_PBE_KEYGEN *keygen);
int EVP_PBE_find(int type, int pbe_nid,
int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen);
void EVP_PBE_cleanup(void);
#define ASN1_PKEY_ALIAS 0x1

View file

@ -3,7 +3,7 @@
* project 1999.
*/
/* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2006 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
@ -67,71 +67,135 @@ static STACK *pbe_algs;
/* Setup a cipher context from a PBE algorithm */
typedef struct {
int pbe_nid;
const EVP_CIPHER *cipher;
const EVP_MD *md;
EVP_PBE_KEYGEN *keygen;
} EVP_PBE_CTL;
typedef struct
{
int pbe_type;
int pbe_nid;
int cipher_nid;
int md_nid;
EVP_PBE_KEYGEN *keygen;
} EVP_PBE_CTL;
int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
{
{
const EVP_CIPHER *cipher;
const EVP_MD *md;
int cipher_nid, md_nid;
EVP_PBE_KEYGEN *keygen;
EVP_PBE_CTL *pbetmp, pbelu;
int i;
pbelu.pbe_nid = OBJ_obj2nid(pbe_obj);
if (pbelu.pbe_nid != NID_undef) i = sk_find(pbe_algs, (char *)&pbelu);
else i = -1;
if (i == -1) {
if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
&cipher_nid, &md_nid, &keygen))
{
char obj_tmp[80];
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_PBE_ALGORITHM);
if (!pbe_obj) BUF_strlcpy (obj_tmp, "NULL", sizeof obj_tmp);
else i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj);
ERR_add_error_data(2, "TYPE=", obj_tmp);
return 0;
}
if(!pass) passlen = 0;
else if (passlen == -1) passlen = strlen(pass);
pbetmp = (EVP_PBE_CTL *)sk_value (pbe_algs, i);
i = (*pbetmp->keygen)(ctx, pass, passlen, param, pbetmp->cipher,
pbetmp->md, en_de);
if (!i) {
}
if(!pass)
passlen = 0;
else if (passlen == -1)
passlen = strlen(pass);
if (cipher_nid == -1)
cipher = NULL;
else
cipher = EVP_get_cipherbynid(cipher_nid);
if (md_nid == -1)
md = NULL;
else
md = EVP_get_digestbynid(md_nid);
if (!keygen(ctx, pass, passlen, param, cipher, md, en_de))
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_KEYGEN_FAILURE);
return 0;
}
}
return 1;
}
static int pbe_cmp(const char * const *a, const char * const *b)
{
{
const EVP_PBE_CTL * const *pbe1 = (const EVP_PBE_CTL * const *) a,
* const *pbe2 = (const EVP_PBE_CTL * const *)b;
return ((*pbe1)->pbe_nid - (*pbe2)->pbe_nid);
}
int ret = (*pbe1)->pbe_type - (*pbe2)->pbe_type;
if (ret)
return ret;
else
return (*pbe1)->pbe_nid - (*pbe2)->pbe_nid;
}
/* Add a PBE algorithm */
int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid, int md_nid,
EVP_PBE_KEYGEN *keygen)
{
{
EVP_PBE_CTL *pbe_tmp;
if (!pbe_algs) pbe_algs = sk_new(pbe_cmp);
if (!(pbe_tmp = (EVP_PBE_CTL*) OPENSSL_malloc (sizeof(EVP_PBE_CTL)))) {
if (!pbe_algs)
pbe_algs = sk_new(pbe_cmp);
if (!(pbe_tmp = (EVP_PBE_CTL*) OPENSSL_malloc (sizeof(EVP_PBE_CTL))))
{
EVPerr(EVP_F_EVP_PBE_ALG_ADD,ERR_R_MALLOC_FAILURE);
return 0;
}
pbe_tmp->pbe_nid = nid;
pbe_tmp->cipher = cipher;
pbe_tmp->md = md;
}
pbe_tmp->pbe_type = pbe_type;
pbe_tmp->pbe_nid = pbe_nid;
pbe_tmp->cipher_nid = cipher_nid;
pbe_tmp->md_nid = md_nid;
pbe_tmp->keygen = keygen;
sk_push (pbe_algs, (char *)pbe_tmp);
return 1;
}
}
int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
EVP_PBE_KEYGEN *keygen)
{
int cipher_nid, md_nid;
if (cipher)
cipher_nid = EVP_CIPHER_type(cipher);
else
cipher_nid = -1;
if (md)
md_nid = EVP_MD_type(md);
else
md_nid = -1;
return EVP_PBE_alg_add_type(EVP_PBE_TYPE_OUTER, nid,
cipher_nid, md_nid, keygen);
}
int EVP_PBE_find(int type, int pbe_nid,
int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen)
{
EVP_PBE_CTL *pbetmp, pbelu;
int i;
if (pbe_nid == NID_undef)
return 0;
pbelu.pbe_type = type;
pbelu.pbe_nid = pbe_nid;
i = sk_find(pbe_algs, (char *)&pbelu);
if (i == -1)
return 0;
pbetmp = (EVP_PBE_CTL *)sk_value (pbe_algs, i);
if (pcnid)
*pcnid = pbetmp->cipher_nid;
if (pmnid)
*pmnid = pbetmp->md_nid;
if (pkeygen)
*pkeygen = pbetmp->keygen;
return 1;
}
void EVP_PBE_cleanup(void)
{
{
sk_pop_free(pbe_algs, OPENSSL_freeFunc);
pbe_algs = NULL;
}
}

View file

@ -97,6 +97,7 @@ EVP_PBE_alg_add(NID_pbeWithSHA1AndRC2_CBC, EVP_rc2_64_cbc(), EVP_sha1(),
#endif
#ifndef OPENSSL_NO_HMAC
EVP_PBE_alg_add(NID_pbes2, NULL, NULL, PKCS5_v2_PBE_keyivgen);
EVP_PBE_alg_add_type(EVP_PBE_TYPE_PRF, NID_hmacWithSHA1, -1, NID_sha1, 0);
#endif
}

View file

@ -3,7 +3,7 @@
* project 1999.
*/
/* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2006 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
@ -71,28 +71,36 @@
#endif
/* 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
* derivation function PBKDF2.
* SHA1 version 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,
int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
const unsigned char *salt, int saltlen, int iter,
const EVP_MD *digest,
int keylen, unsigned char *out)
{
unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4];
int cplen, j, k, tkeylen;
{
unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
int cplen, j, k, tkeylen, mdlen;
unsigned long i = 1;
HMAC_CTX hctx;
mdlen = EVP_MD_size(digest);
HMAC_CTX_init(&hctx);
p = out;
tkeylen = keylen;
if(!pass) passlen = 0;
else if(passlen == -1) passlen = strlen(pass);
while(tkeylen) {
if(tkeylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH;
else cplen = tkeylen;
if(!pass)
passlen = 0;
else if(passlen == -1)
passlen = strlen(pass);
while(tkeylen)
{
if(tkeylen > mdlen)
cplen = mdlen;
else
cplen = tkeylen;
/* We are unlikely to ever use more than 256 blocks (5120 bits!)
* but just in case...
*/
@ -100,20 +108,22 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
itmp[1] = (unsigned char)((i >> 16) & 0xff);
itmp[2] = (unsigned char)((i >> 8) & 0xff);
itmp[3] = (unsigned char)(i & 0xff);
HMAC_Init_ex(&hctx, pass, passlen, EVP_sha1(), NULL);
HMAC_Init_ex(&hctx, pass, passlen, digest, NULL);
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];
}
for(j = 1; j < iter; j++)
{
HMAC(digest, pass, passlen,
digtmp, mdlen, digtmp, NULL);
for(k = 0; k < cplen; k++)
p[k] ^= digtmp[k];
}
tkeylen-= cplen;
i++;
p+= cplen;
}
}
HMAC_CTX_cleanup(&hctx);
#ifdef DEBUG_PKCS5V2
fprintf(stderr, "Password:\n");
@ -125,7 +135,15 @@ int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
h__dump (out, keylen);
#endif
return 1;
}
}
int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
const unsigned char *salt, int saltlen, int iter,
int keylen, unsigned char *out)
{
return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha1(),
keylen, out);
}
#ifdef DO_TEST
main()
@ -155,6 +173,8 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
PBE2PARAM *pbe2 = NULL;
const EVP_CIPHER *cipher;
PBKDF2PARAM *kdf = NULL;
const EVP_MD *prfmd;
int prf_nid, hmac_md_nid;
if (param == NULL || param->type != V_ASN1_SEQUENCE ||
param->value.sequence == NULL) {
@ -226,10 +246,23 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
goto err;
}
if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) {
if (kdf->prf)
prf_nid = OBJ_obj2nid(kdf->prf->algorithm);
else
prf_nid = NID_hmacWithSHA1;
if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0))
{
EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
goto err;
}
}
prfmd = EVP_get_digestbynid(hmac_md_nid);
if (prfmd == NULL)
{
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,
@ -241,7 +274,8 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
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);
PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd,
keylen, key);
EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
OPENSSL_cleanse(key, keylen);
PBKDF2PARAM_free(kdf);

View file

@ -62,12 +62,12 @@
* [including the GNU Public Licence.]
*/
#define NUM_NID 802
#define NUM_SN 798
#define NUM_LN 798
#define NUM_OBJ 760
#define NUM_NID 803
#define NUM_SN 799
#define NUM_LN 799
#define NUM_OBJ 761
static unsigned char lvalues[5345]={
static unsigned char lvalues[5353]={
0x00, /* [ 0] OBJ_undef */
0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 1] OBJ_rsadsi */
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 7] OBJ_pkcs */
@ -828,6 +828,7 @@ static unsigned char lvalues[5345]={
0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x03, /* [5320] OBJ_id_GostR3411_94_with_GostR3410_94_cc */
0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x04, /* [5328] OBJ_id_GostR3411_94_with_GostR3410_2001_cc */
0x2A,0x85,0x03,0x02,0x09,0x01,0x08,0x01, /* [5336] OBJ_id_GostR3410_2001_ParamSet_cc */
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x06, /* [5344] OBJ_hmacWithMD5 */
};
static ASN1_OBJECT nid_objs[NUM_NID]={
@ -2122,6 +2123,7 @@ static ASN1_OBJECT nid_objs[NUM_NID]={
{"id-GostR3410-2001-ParamSet-cc",
"GOST R 3410-2001 Parameter Set Cryptocom",
NID_id_GostR3410_2001_ParamSet_cc,8,&(lvalues[5336]),0},
{"hmacWithMD5","hmacWithMD5",NID_hmacWithMD5,8,&(lvalues[5344]),0},
};
static ASN1_OBJECT *sn_objs[NUM_SN]={
@ -2372,6 +2374,7 @@ static ASN1_OBJECT *sn_objs[NUM_SN]={
&(nid_objs[784]),/* "gost89" */
&(nid_objs[757]),/* "gost94" */
&(nid_objs[797]),/* "gost94cc" */
&(nid_objs[802]),/* "hmacWithMD5" */
&(nid_objs[163]),/* "hmacWithSHA1" */
&(nid_objs[432]),/* "holdInstructionCallIssuer" */
&(nid_objs[430]),/* "holdInstructionCode" */
@ -3186,6 +3189,7 @@ static ASN1_OBJECT *ln_objs[NUM_LN]={
&(nid_objs[509]),/* "generationQualifier" */
&(nid_objs[601]),/* "generic cryptogram" */
&(nid_objs[99]),/* "givenName" */
&(nid_objs[802]),/* "hmacWithMD5" */
&(nid_objs[163]),/* "hmacWithSHA1" */
&(nid_objs[486]),/* "homePostalAddress" */
&(nid_objs[473]),/* "homeTelephoneNumber" */
@ -4094,6 +4098,7 @@ static ASN1_OBJECT *obj_objs[NUM_OBJ]={
&(nid_objs[ 3]),/* OBJ_md2 1 2 840 113549 2 2 */
&(nid_objs[257]),/* OBJ_md4 1 2 840 113549 2 4 */
&(nid_objs[ 4]),/* OBJ_md5 1 2 840 113549 2 5 */
&(nid_objs[802]),/* OBJ_hmacWithMD5 1 2 840 113549 2 6 */
&(nid_objs[163]),/* OBJ_hmacWithSHA1 1 2 840 113549 2 7 */
&(nid_objs[37]),/* OBJ_rc2_cbc 1 2 840 113549 3 2 */
&(nid_objs[ 5]),/* OBJ_rc4 1 2 840 113549 3 4 */

View file

@ -1075,6 +1075,10 @@
#define LN_md5_sha1 "md5-sha1"
#define NID_md5_sha1 114
#define LN_hmacWithMD5 "hmacWithMD5"
#define NID_hmacWithMD5 802
#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L
#define LN_hmacWithSHA1 "hmacWithSHA1"
#define NID_hmacWithSHA1 163
#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L

View file

@ -799,3 +799,4 @@ id_GostR3410_2001_cc 798
id_GostR3411_94_with_GostR3410_94_cc 799
id_GostR3411_94_with_GostR3410_2001_cc 800
id_GostR3410_2001_ParamSet_cc 801
hmacWithMD5 802

View file

@ -338,6 +338,7 @@ rsadsi 2 2 : MD2 : md2
rsadsi 2 4 : MD4 : md4
rsadsi 2 5 : MD5 : md5
: MD5-SHA1 : md5-sha1
rsadsi 2 6 : : hmacWithMD5
rsadsi 2 7 : : hmacWithSHA1
rsadsi 3 2 : RC2-CBC : rc2-cbc
: RC2-ECB : rc2-ecb