1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ssl/libcrypto/src/crypto/evp/p5_crpt2.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,263 @@
1.4 +/* p5_crpt2.c */
1.5 +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
1.6 + * project 1999.
1.7 + */
1.8 +/* ====================================================================
1.9 + * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
1.10 + *
1.11 + * Redistribution and use in source and binary forms, with or without
1.12 + * modification, are permitted provided that the following conditions
1.13 + * are met:
1.14 + *
1.15 + * 1. Redistributions of source code must retain the above copyright
1.16 + * notice, this list of conditions and the following disclaimer.
1.17 + *
1.18 + * 2. Redistributions in binary form must reproduce the above copyright
1.19 + * notice, this list of conditions and the following disclaimer in
1.20 + * the documentation and/or other materials provided with the
1.21 + * distribution.
1.22 + *
1.23 + * 3. All advertising materials mentioning features or use of this
1.24 + * software must display the following acknowledgment:
1.25 + * "This product includes software developed by the OpenSSL Project
1.26 + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
1.27 + *
1.28 + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
1.29 + * endorse or promote products derived from this software without
1.30 + * prior written permission. For written permission, please contact
1.31 + * licensing@OpenSSL.org.
1.32 + *
1.33 + * 5. Products derived from this software may not be called "OpenSSL"
1.34 + * nor may "OpenSSL" appear in their names without prior written
1.35 + * permission of the OpenSSL Project.
1.36 + *
1.37 + * 6. Redistributions of any form whatsoever must retain the following
1.38 + * acknowledgment:
1.39 + * "This product includes software developed by the OpenSSL Project
1.40 + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
1.41 + *
1.42 + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
1.43 + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1.44 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.45 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
1.46 + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1.47 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1.48 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1.49 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1.50 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
1.51 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1.52 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1.53 + * OF THE POSSIBILITY OF SUCH DAMAGE.
1.54 + * ====================================================================
1.55 + *
1.56 + * This product includes cryptographic software written by Eric Young
1.57 + * (eay@cryptsoft.com). This product includes software written by Tim
1.58 + * Hudson (tjh@cryptsoft.com).
1.59 + *
1.60 + */
1.61 +#include <stdio.h>
1.62 +#include <stdlib.h>
1.63 +#include "cryptlib.h"
1.64 +#if !defined(OPENSSL_NO_HMAC) && !defined(OPENSSL_NO_SHA)
1.65 +#include <openssl/x509.h>
1.66 +#include <openssl/evp.h>
1.67 +#include <openssl/hmac.h>
1.68 +
1.69 +/* set this to print out info about the keygen algorithm */
1.70 +/* #define DEBUG_PKCS5V2 */
1.71 +
1.72 +#ifdef DEBUG_PKCS5V2
1.73 + static void h__dump (const unsigned char *p, int len);
1.74 +#endif
1.75 +
1.76 +/* This is an implementation of PKCS#5 v2.0 password based encryption key
1.77 + * derivation function PBKDF2 using the only currently defined function HMAC
1.78 + * with SHA1. Verified against test vectors posted by Peter Gutmann
1.79 + * <pgut001@cs.auckland.ac.nz> to the PKCS-TNG <pkcs-tng@rsa.com> mailing list.
1.80 + */
1.81 +
1.82 +EXPORT_C int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
1.83 + const unsigned char *salt, int saltlen, int iter,
1.84 + int keylen, unsigned char *out)
1.85 +{
1.86 + unsigned char digtmp[SHA_DIGEST_LENGTH], *p, itmp[4];
1.87 + int cplen, j, k, tkeylen;
1.88 + unsigned long i = 1;
1.89 + HMAC_CTX hctx;
1.90 +
1.91 + HMAC_CTX_init(&hctx);
1.92 + p = out;
1.93 + tkeylen = keylen;
1.94 + if(!pass) passlen = 0;
1.95 + else if(passlen == -1) passlen = strlen(pass);
1.96 + while(tkeylen) {
1.97 + if(tkeylen > SHA_DIGEST_LENGTH) cplen = SHA_DIGEST_LENGTH;
1.98 + else cplen = tkeylen;
1.99 + /* We are unlikely to ever use more than 256 blocks (5120 bits!)
1.100 + * but just in case...
1.101 + */
1.102 + itmp[0] = (unsigned char)((i >> 24) & 0xff);
1.103 + itmp[1] = (unsigned char)((i >> 16) & 0xff);
1.104 + itmp[2] = (unsigned char)((i >> 8) & 0xff);
1.105 + itmp[3] = (unsigned char)(i & 0xff);
1.106 + HMAC_Init_ex(&hctx, pass, passlen, EVP_sha1(), NULL);
1.107 + HMAC_Update(&hctx, salt, saltlen);
1.108 + HMAC_Update(&hctx, itmp, 4);
1.109 + HMAC_Final(&hctx, digtmp, NULL);
1.110 + memcpy(p, digtmp, cplen);
1.111 + for(j = 1; j < iter; j++) {
1.112 + HMAC(EVP_sha1(), pass, passlen,
1.113 + digtmp, SHA_DIGEST_LENGTH, digtmp, NULL);
1.114 + for(k = 0; k < cplen; k++) p[k] ^= digtmp[k];
1.115 + }
1.116 + tkeylen-= cplen;
1.117 + i++;
1.118 + p+= cplen;
1.119 + }
1.120 + HMAC_CTX_cleanup(&hctx);
1.121 +#ifdef DEBUG_PKCS5V2
1.122 + fprintf(stderr, "Password:\n");
1.123 + h__dump (pass, passlen);
1.124 + fprintf(stderr, "Salt:\n");
1.125 + h__dump (salt, saltlen);
1.126 + fprintf(stderr, "Iteration count %d\n", iter);
1.127 + fprintf(stderr, "Key:\n");
1.128 + h__dump (out, keylen);
1.129 +#endif
1.130 + return 1;
1.131 +}
1.132 +
1.133 +#ifdef DO_TEST
1.134 +main()
1.135 +{
1.136 + unsigned char out[4];
1.137 + unsigned char salt[] = {0x12, 0x34, 0x56, 0x78};
1.138 + PKCS5_PBKDF2_HMAC_SHA1("password", -1, salt, 4, 5, 4, out);
1.139 + fprintf(stderr, "Out %02X %02X %02X %02X\n",
1.140 + out[0], out[1], out[2], out[3]);
1.141 +}
1.142 +
1.143 +#endif
1.144 +
1.145 +/* Now the key derivation function itself. This is a bit evil because
1.146 + * it has to check the ASN1 parameters are valid: and there are quite a
1.147 + * few of them...
1.148 + */
1.149 +
1.150 +EXPORT_C int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
1.151 + ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md,
1.152 + int en_de)
1.153 +{
1.154 + unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
1.155 + const unsigned char *pbuf;
1.156 + int saltlen, iter, plen;
1.157 + unsigned int keylen;
1.158 + PBE2PARAM *pbe2 = NULL;
1.159 + const EVP_CIPHER *cipher;
1.160 + PBKDF2PARAM *kdf = NULL;
1.161 +
1.162 + if (param == NULL || param->type != V_ASN1_SEQUENCE ||
1.163 + param->value.sequence == NULL) {
1.164 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
1.165 + return 0;
1.166 + }
1.167 +
1.168 + pbuf = param->value.sequence->data;
1.169 + plen = param->value.sequence->length;
1.170 + if(!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) {
1.171 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
1.172 + return 0;
1.173 + }
1.174 +
1.175 + /* See if we recognise the key derivation function */
1.176 +
1.177 + if(OBJ_obj2nid(pbe2->keyfunc->algorithm) != NID_id_pbkdf2) {
1.178 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
1.179 + EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
1.180 + goto err;
1.181 + }
1.182 +
1.183 + /* lets see if we recognise the encryption algorithm.
1.184 + */
1.185 +
1.186 + cipher = EVP_get_cipherbyname(
1.187 + OBJ_nid2sn(OBJ_obj2nid(pbe2->encryption->algorithm)));
1.188 +
1.189 + if(!cipher) {
1.190 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
1.191 + EVP_R_UNSUPPORTED_CIPHER);
1.192 + goto err;
1.193 + }
1.194 +
1.195 + /* Fixup cipher based on AlgorithmIdentifier */
1.196 + EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de);
1.197 + if(EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) {
1.198 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
1.199 + EVP_R_CIPHER_PARAMETER_ERROR);
1.200 + goto err;
1.201 + }
1.202 + keylen = EVP_CIPHER_CTX_key_length(ctx);
1.203 + OPENSSL_assert(keylen <= sizeof key);
1.204 +
1.205 + /* Now decode key derivation function */
1.206 +
1.207 + if(!pbe2->keyfunc->parameter ||
1.208 + (pbe2->keyfunc->parameter->type != V_ASN1_SEQUENCE))
1.209 + {
1.210 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
1.211 + goto err;
1.212 + }
1.213 +
1.214 + pbuf = pbe2->keyfunc->parameter->value.sequence->data;
1.215 + plen = pbe2->keyfunc->parameter->value.sequence->length;
1.216 + if(!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen)) ) {
1.217 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
1.218 + goto err;
1.219 + }
1.220 +
1.221 + PBE2PARAM_free(pbe2);
1.222 + pbe2 = NULL;
1.223 +
1.224 + /* Now check the parameters of the kdf */
1.225 +
1.226 + if(kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)){
1.227 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
1.228 + EVP_R_UNSUPPORTED_KEYLENGTH);
1.229 + goto err;
1.230 + }
1.231 +
1.232 + if(kdf->prf && (OBJ_obj2nid(kdf->prf->algorithm) != NID_hmacWithSHA1)) {
1.233 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
1.234 + goto err;
1.235 + }
1.236 +
1.237 + if(kdf->salt->type != V_ASN1_OCTET_STRING) {
1.238 + EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
1.239 + EVP_R_UNSUPPORTED_SALT_TYPE);
1.240 + goto err;
1.241 + }
1.242 +
1.243 + /* it seems that its all OK */
1.244 + salt = kdf->salt->value.octet_string->data;
1.245 + saltlen = kdf->salt->value.octet_string->length;
1.246 + iter = ASN1_INTEGER_get(kdf->iter);
1.247 + PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, salt, saltlen, iter, keylen, key);
1.248 + EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
1.249 + OPENSSL_cleanse(key, keylen);
1.250 + PBKDF2PARAM_free(kdf);
1.251 + return 1;
1.252 +
1.253 + err:
1.254 + PBE2PARAM_free(pbe2);
1.255 + PBKDF2PARAM_free(kdf);
1.256 + return 0;
1.257 +}
1.258 +
1.259 +#ifdef DEBUG_PKCS5V2
1.260 +static void h__dump (const unsigned char *p, int len)
1.261 +{
1.262 + for (; len --; p++) fprintf(stderr, "%02X ", *p);
1.263 + fprintf(stderr, "\n");
1.264 +}
1.265 +#endif
1.266 +#endif