os/ossrv/ssl/libcrypto/src/crypto/evp/p5_crpt2.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* p5_crpt2.c */
sl@0
     2
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
sl@0
     3
 * project 1999.
sl@0
     4
 */
sl@0
     5
/* ====================================================================
sl@0
     6
 * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
sl@0
     7
 *
sl@0
     8
 * Redistribution and use in source and binary forms, with or without
sl@0
     9
 * modification, are permitted provided that the following conditions
sl@0
    10
 * are met:
sl@0
    11
 *
sl@0
    12
 * 1. Redistributions of source code must retain the above copyright
sl@0
    13
 *    notice, this list of conditions and the following disclaimer. 
sl@0
    14
 *
sl@0
    15
 * 2. Redistributions in binary form must reproduce the above copyright
sl@0
    16
 *    notice, this list of conditions and the following disclaimer in
sl@0
    17
 *    the documentation and/or other materials provided with the
sl@0
    18
 *    distribution.
sl@0
    19
 *
sl@0
    20
 * 3. All advertising materials mentioning features or use of this
sl@0
    21
 *    software must display the following acknowledgment:
sl@0
    22
 *    "This product includes software developed by the OpenSSL Project
sl@0
    23
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
sl@0
    24
 *
sl@0
    25
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
sl@0
    26
 *    endorse or promote products derived from this software without
sl@0
    27
 *    prior written permission. For written permission, please contact
sl@0
    28
 *    licensing@OpenSSL.org.
sl@0
    29
 *
sl@0
    30
 * 5. Products derived from this software may not be called "OpenSSL"
sl@0
    31
 *    nor may "OpenSSL" appear in their names without prior written
sl@0
    32
 *    permission of the OpenSSL Project.
sl@0
    33
 *
sl@0
    34
 * 6. Redistributions of any form whatsoever must retain the following
sl@0
    35
 *    acknowledgment:
sl@0
    36
 *    "This product includes software developed by the OpenSSL Project
sl@0
    37
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
sl@0
    38
 *
sl@0
    39
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
sl@0
    40
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0
    41
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
sl@0
    42
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
sl@0
    43
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
sl@0
    44
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
sl@0
    45
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
sl@0
    46
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0
    47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
sl@0
    48
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
sl@0
    49
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
sl@0
    50
 * OF THE POSSIBILITY OF SUCH DAMAGE.
sl@0
    51
 * ====================================================================
sl@0
    52
 *
sl@0
    53
 * This product includes cryptographic software written by Eric Young
sl@0
    54
 * (eay@cryptsoft.com).  This product includes software written by Tim
sl@0
    55
 * Hudson (tjh@cryptsoft.com).
sl@0
    56
 *
sl@0
    57
 */
sl@0
    58
#include <stdio.h>
sl@0
    59
#include <stdlib.h>
sl@0
    60
#include "cryptlib.h"
sl@0
    61
#if !defined(OPENSSL_NO_HMAC) && !defined(OPENSSL_NO_SHA)
sl@0
    62
#include <openssl/x509.h>
sl@0
    63
#include <openssl/evp.h>
sl@0
    64
#include <openssl/hmac.h>
sl@0
    65
sl@0
    66
/* set this to print out info about the keygen algorithm */
sl@0
    67
/* #define DEBUG_PKCS5V2 */
sl@0
    68
sl@0
    69
#ifdef DEBUG_PKCS5V2
sl@0
    70
	static void h__dump (const unsigned char *p, int len);
sl@0
    71
#endif
sl@0
    72
sl@0
    73
/* This is an implementation of PKCS#5 v2.0 password based encryption key
sl@0
    74
 * derivation function PBKDF2 using the only currently defined function HMAC
sl@0
    75
 * with SHA1. Verified against test vectors posted by Peter Gutmann
sl@0
    76
 * <pgut001@cs.auckland.ac.nz> to the PKCS-TNG <pkcs-tng@rsa.com> mailing list.
sl@0
    77
 */
sl@0
    78
sl@0
    79
EXPORT_C int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
sl@0
    80
			   const unsigned char *salt, int saltlen, int iter,
sl@0
    81
			   int keylen, unsigned char *out)
sl@0
    82
{
sl@0
    83
	unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4];
sl@0
    84
	int cplen, j, k, tkeylen;
sl@0
    85
	unsigned long i = 1;
sl@0
    86
	HMAC_CTX hctx;
sl@0
    87
sl@0
    88
	HMAC_CTX_init(&hctx);
sl@0
    89
	p = out;
sl@0
    90
	tkeylen = keylen;
sl@0
    91
	if(!pass) passlen = 0;
sl@0
    92
	else if(passlen == -1) passlen = strlen(pass);
sl@0
    93
	while(tkeylen) {
sl@0
    94
		if(tkeylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH;
sl@0
    95
		else cplen = tkeylen;
sl@0
    96
		/* We are unlikely to ever use more than 256 blocks (5120 bits!)
sl@0
    97
		 * but just in case...
sl@0
    98
		 */
sl@0
    99
		itmp[0] = (unsigned char)((i >> 24) & 0xff);
sl@0
   100
		itmp[1] = (unsigned char)((i >> 16) & 0xff);
sl@0
   101
		itmp[2] = (unsigned char)((i >> 8) & 0xff);
sl@0
   102
		itmp[3] = (unsigned char)(i & 0xff);
sl@0
   103
		HMAC_Init_ex(&hctx, pass, passlen, EVP_sha1(), NULL);
sl@0
   104
		HMAC_Update(&hctx, salt, saltlen);
sl@0
   105
		HMAC_Update(&hctx, itmp, 4);
sl@0
   106
		HMAC_Final(&hctx, digtmp, NULL);
sl@0
   107
		memcpy(p, digtmp, cplen);
sl@0
   108
		for(j = 1; j < iter; j++) {
sl@0
   109
			HMAC(EVP_sha1(), pass, passlen,
sl@0
   110
				 digtmp, SHA_DIGEST_LENGTH, digtmp, NULL);
sl@0
   111
			for(k = 0; k < cplen; k++) p[k] ^= digtmp[k];
sl@0
   112
		}
sl@0
   113
		tkeylen-= cplen;
sl@0
   114
		i++;
sl@0
   115
		p+= cplen;
sl@0
   116
	}
sl@0
   117
	HMAC_CTX_cleanup(&hctx);
sl@0
   118
#ifdef DEBUG_PKCS5V2
sl@0
   119
	fprintf(stderr, "Password:\n");
sl@0
   120
	h__dump (pass, passlen);
sl@0
   121
	fprintf(stderr, "Salt:\n");
sl@0
   122
	h__dump (salt, saltlen);
sl@0
   123
	fprintf(stderr, "Iteration count %d\n", iter);
sl@0
   124
	fprintf(stderr, "Key:\n");
sl@0
   125
	h__dump (out, keylen);
sl@0
   126
#endif
sl@0
   127
	return 1;
sl@0
   128
}
sl@0
   129
sl@0
   130
#ifdef DO_TEST
sl@0
   131
main()
sl@0
   132
{
sl@0
   133
	unsigned char out[4];
sl@0
   134
	unsigned char salt[] = {0x12, 0x34, 0x56, 0x78};
sl@0
   135
	PKCS5_PBKDF2_HMAC_SHA1("password", -1, salt, 4, 5, 4, out);
sl@0
   136
	fprintf(stderr, "Out %02X %02X %02X %02X\n",
sl@0
   137
					 out[0], out[1], out[2], out[3]);
sl@0
   138
}
sl@0
   139
sl@0
   140
#endif
sl@0
   141
sl@0
   142
/* Now the key derivation function itself. This is a bit evil because
sl@0
   143
 * it has to check the ASN1 parameters are valid: and there are quite a
sl@0
   144
 * few of them...
sl@0
   145
 */
sl@0
   146
sl@0
   147
EXPORT_C int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
sl@0
   148
                         ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md,
sl@0
   149
                         int en_de)
sl@0
   150
{
sl@0
   151
	unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
sl@0
   152
	const unsigned char *pbuf;
sl@0
   153
	int saltlen, iter, plen;
sl@0
   154
	unsigned int keylen;
sl@0
   155
	PBE2PARAM *pbe2 = NULL;
sl@0
   156
	const EVP_CIPHER *cipher;
sl@0
   157
	PBKDF2PARAM *kdf = NULL;
sl@0
   158
sl@0
   159
	if (param == NULL || param->type != V_ASN1_SEQUENCE ||
sl@0
   160
	    param->value.sequence == NULL) {
sl@0
   161
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
sl@0
   162
		return 0;
sl@0
   163
	}
sl@0
   164
sl@0
   165
	pbuf = param->value.sequence->data;
sl@0
   166
	plen = param->value.sequence->length;
sl@0
   167
	if(!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) {
sl@0
   168
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
sl@0
   169
		return 0;
sl@0
   170
	}
sl@0
   171
sl@0
   172
	/* See if we recognise the key derivation function */
sl@0
   173
sl@0
   174
	if(OBJ_obj2nid(pbe2->keyfunc->algorithm) != NID_id_pbkdf2) {
sl@0
   175
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
sl@0
   176
				EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
sl@0
   177
		goto err;
sl@0
   178
	}
sl@0
   179
sl@0
   180
	/* lets see if we recognise the encryption algorithm.
sl@0
   181
	 */
sl@0
   182
sl@0
   183
	cipher = EVP_get_cipherbyname(
sl@0
   184
			OBJ_nid2sn(OBJ_obj2nid(pbe2->encryption->algorithm)));
sl@0
   185
sl@0
   186
	if(!cipher) {
sl@0
   187
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
sl@0
   188
						EVP_R_UNSUPPORTED_CIPHER);
sl@0
   189
		goto err;
sl@0
   190
	}
sl@0
   191
sl@0
   192
	/* Fixup cipher based on AlgorithmIdentifier */
sl@0
   193
	EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de);
sl@0
   194
	if(EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) {
sl@0
   195
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
sl@0
   196
					EVP_R_CIPHER_PARAMETER_ERROR);
sl@0
   197
		goto err;
sl@0
   198
	}
sl@0
   199
	keylen = EVP_CIPHER_CTX_key_length(ctx);
sl@0
   200
	OPENSSL_assert(keylen <= sizeof key);
sl@0
   201
sl@0
   202
	/* Now decode key derivation function */
sl@0
   203
sl@0
   204
	if(!pbe2->keyfunc->parameter ||
sl@0
   205
		 (pbe2->keyfunc->parameter->type != V_ASN1_SEQUENCE))
sl@0
   206
		{
sl@0
   207
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
sl@0
   208
		goto err;
sl@0
   209
		}
sl@0
   210
sl@0
   211
	pbuf = pbe2->keyfunc->parameter->value.sequence->data;
sl@0
   212
	plen = pbe2->keyfunc->parameter->value.sequence->length;
sl@0
   213
	if(!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen)) ) {
sl@0
   214
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
sl@0
   215
		goto err;
sl@0
   216
	}
sl@0
   217
sl@0
   218
	PBE2PARAM_free(pbe2);
sl@0
   219
	pbe2 = NULL;
sl@0
   220
sl@0
   221
	/* Now check the parameters of the kdf */
sl@0
   222
sl@0
   223
	if(kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)){
sl@0
   224
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
sl@0
   225
						EVP_R_UNSUPPORTED_KEYLENGTH);
sl@0
   226
		goto err;
sl@0
   227
	}
sl@0
   228
sl@0
   229
	if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) {
sl@0
   230
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
sl@0
   231
		goto err;
sl@0
   232
	}
sl@0
   233
sl@0
   234
	if(kdf->salt->type != V_ASN1_OCTET_STRING) {
sl@0
   235
		EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
sl@0
   236
						EVP_R_UNSUPPORTED_SALT_TYPE);
sl@0
   237
		goto err;
sl@0
   238
	}
sl@0
   239
sl@0
   240
	/* it seems that its all OK */
sl@0
   241
	salt = kdf->salt->value.octet_string->data;
sl@0
   242
	saltlen = kdf->salt->value.octet_string->length;
sl@0
   243
	iter = ASN1_INTEGER_get(kdf->iter);
sl@0
   244
	PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen, iter, keylen, key);
sl@0
   245
	EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
sl@0
   246
	OPENSSL_cleanse(key, keylen);
sl@0
   247
	PBKDF2PARAM_free(kdf);
sl@0
   248
	return 1;
sl@0
   249
sl@0
   250
	err:
sl@0
   251
	PBE2PARAM_free(pbe2);
sl@0
   252
	PBKDF2PARAM_free(kdf);
sl@0
   253
	return 0;
sl@0
   254
}
sl@0
   255
sl@0
   256
#ifdef DEBUG_PKCS5V2
sl@0
   257
static void h__dump (const unsigned char *p, int len)
sl@0
   258
{
sl@0
   259
        for (; len --; p++) fprintf(stderr, "%02X ", *p);
sl@0
   260
        fprintf(stderr, "\n");
sl@0
   261
}
sl@0
   262
#endif
sl@0
   263
#endif