p5_crpt2.c revision 296341
1139823Simp/* p5_crpt2.c */ 234649Swollman/* 334649Swollman * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 434649Swollman * 1999. 534649Swollman */ 634649Swollman/* ==================================================================== 734649Swollman * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. 834649Swollman * 934649Swollman * Redistribution and use in source and binary forms, with or without 1034649Swollman * modification, are permitted provided that the following conditions 1134649Swollman * are met: 1234649Swollman * 1334649Swollman * 1. Redistributions of source code must retain the above copyright 1434649Swollman * notice, this list of conditions and the following disclaimer. 1534649Swollman * 1634649Swollman * 2. Redistributions in binary form must reproduce the above copyright 1734649Swollman * notice, this list of conditions and the following disclaimer in 1834649Swollman * the documentation and/or other materials provided with the 1934649Swollman * distribution. 2034649Swollman * 2134649Swollman * 3. All advertising materials mentioning features or use of this 2234649Swollman * software must display the following acknowledgment: 2334649Swollman * "This product includes software developed by the OpenSSL Project 2434649Swollman * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2534649Swollman * 2634649Swollman * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2734649Swollman * endorse or promote products derived from this software without 2834649Swollman * prior written permission. For written permission, please contact 2950477Speter * licensing@OpenSSL.org. 3034649Swollman * 3134649Swollman * 5. Products derived from this software may not be called "OpenSSL" 3234649Swollman * nor may "OpenSSL" appear in their names without prior written 3334649Swollman * permission of the OpenSSL Project. 3434649Swollman * 3534649Swollman * 6. Redistributions of any form whatsoever must retain the following 3634649Swollman * acknowledgment: 3734649Swollman * "This product includes software developed by the OpenSSL Project 3834649Swollman * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3934649Swollman * 4034649Swollman * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4134649Swollman * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4234649Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43167126Sbms * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44167126Sbms * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45167126Sbms * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46167126Sbms * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47167126Sbms * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48167126Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49167126Sbms * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5034649Swollman * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51167126Sbms * OF THE POSSIBILITY OF SUCH DAMAGE. 52167126Sbms * ==================================================================== 53167126Sbms * 54167126Sbms * This product includes cryptographic software written by Eric Young 55167126Sbms * (eay@cryptsoft.com). This product includes software written by Tim 56167126Sbms * Hudson (tjh@cryptsoft.com). 57167126Sbms * 58167126Sbms */ 59167126Sbms#include <stdio.h> 60167126Sbms#include <stdlib.h> 61167126Sbms#include "cryptlib.h" 62167126Sbms#if !defined(OPENSSL_NO_HMAC) && !defined(OPENSSL_NO_SHA) 63167126Sbms# include <openssl/x509.h> 64167126Sbms# include <openssl/evp.h> 65167126Sbms# include <openssl/hmac.h> 66167126Sbms# include "evp_locl.h" 67167126Sbms 68167126Sbms/* set this to print out info about the keygen algorithm */ 69167126Sbms/* #define DEBUG_PKCS5V2 */ 70167126Sbms 71167126Sbms# ifdef DEBUG_PKCS5V2 72167126Sbmsstatic void h__dump(const unsigned char *p, int len); 73167126Sbms# endif 74167126Sbms 75167126Sbms/* 76167126Sbms * This is an implementation of PKCS#5 v2.0 password based encryption key 77167126Sbms * derivation function PBKDF2. SHA1 version verified against test vectors 7834649Swollman * posted by Peter Gutmann <pgut001@cs.auckland.ac.nz> to the PKCS-TNG 7934649Swollman * <pkcs-tng@rsa.com> mailing list. 8034649Swollman */ 8134649Swollman 8234649Swollmanint PKCS5_PBKDF2_HMAC(const char *pass, int passlen, 8334649Swollman const unsigned char *salt, int saltlen, int iter, 8434649Swollman const EVP_MD *digest, int keylen, unsigned char *out) 8534649Swollman{ 8634649Swollman unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; 8734649Swollman int cplen, j, k, tkeylen, mdlen; 8834649Swollman unsigned long i = 1; 8934649Swollman HMAC_CTX hctx_tpl, hctx; 9034649Swollman 9134649Swollman mdlen = EVP_MD_size(digest); 92106932Ssam if (mdlen < 0) 93106932Ssam return 0; 94106932Ssam 95106932Ssam HMAC_CTX_init(&hctx_tpl); 96124683Syar p = out; 97106932Ssam tkeylen = keylen; 98124683Syar if (!pass) 99124683Syar passlen = 0; 100106932Ssam else if (passlen == -1) 101106932Ssam passlen = strlen(pass); 102106932Ssam if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL)) { 103106932Ssam HMAC_CTX_cleanup(&hctx_tpl); 104162375Sandre return 0; 105162375Sandre } 106106932Ssam while (tkeylen) { 107162375Sandre if (tkeylen > mdlen) 108162375Sandre cplen = mdlen; 109162375Sandre else 110162375Sandre cplen = tkeylen; 111162375Sandre /* 112162375Sandre * We are unlikely to ever use more than 256 blocks (5120 bits!) but 113106932Ssam * just in case... 114162375Sandre */ 115106932Ssam itmp[0] = (unsigned char)((i >> 24) & 0xff); 116162375Sandre itmp[1] = (unsigned char)((i >> 16) & 0xff); 117162375Sandre itmp[2] = (unsigned char)((i >> 8) & 0xff); 118162375Sandre itmp[3] = (unsigned char)(i & 0xff); 119162375Sandre if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { 120162375Sandre HMAC_CTX_cleanup(&hctx_tpl); 121106932Ssam return 0; 122106932Ssam } 123106932Ssam if (!HMAC_Update(&hctx, salt, saltlen) 124106932Ssam || !HMAC_Update(&hctx, itmp, 4) 125162375Sandre || !HMAC_Final(&hctx, digtmp, NULL)) { 126162375Sandre HMAC_CTX_cleanup(&hctx_tpl); 127106932Ssam HMAC_CTX_cleanup(&hctx); 128106932Ssam return 0; 129155051Sglebius } 130155051Sglebius HMAC_CTX_cleanup(&hctx); 131155051Sglebius memcpy(p, digtmp, cplen); 132155051Sglebius for (j = 1; j < iter; j++) { 133155051Sglebius if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { 134219819Sjeff HMAC_CTX_cleanup(&hctx_tpl); 135219819Sjeff return 0; 136219819Sjeff } 137219819Sjeff if (!HMAC_Update(&hctx, digtmp, mdlen) 138219819Sjeff || !HMAC_Final(&hctx, digtmp, NULL)) { 139219819Sjeff HMAC_CTX_cleanup(&hctx_tpl); 140219819Sjeff HMAC_CTX_cleanup(&hctx); 141219819Sjeff return 0; 142219819Sjeff } 143219819Sjeff HMAC_CTX_cleanup(&hctx); 144219819Sjeff for (k = 0; k < cplen; k++) 145219819Sjeff p[k] ^= digtmp[k]; 146155051Sglebius } 147219819Sjeff tkeylen -= cplen; 148219819Sjeff i++; 149219819Sjeff p += cplen; 150219819Sjeff } 151219819Sjeff HMAC_CTX_cleanup(&hctx_tpl); 152219819Sjeff# ifdef DEBUG_PKCS5V2 153106932Ssam fprintf(stderr, "Password:\n"); 154106932Ssam h__dump(pass, passlen); 15534649Swollman fprintf(stderr, "Salt:\n"); 156 h__dump(salt, saltlen); 157 fprintf(stderr, "Iteration count %d\n", iter); 158 fprintf(stderr, "Key:\n"); 159 h__dump(out, keylen); 160# endif 161 return 1; 162} 163 164int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, 165 const unsigned char *salt, int saltlen, int iter, 166 int keylen, unsigned char *out) 167{ 168 return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha1(), 169 keylen, out); 170} 171 172# ifdef DO_TEST 173main() 174{ 175 unsigned char out[4]; 176 unsigned char salt[] = { 0x12, 0x34, 0x56, 0x78 }; 177 PKCS5_PBKDF2_HMAC_SHA1("password", -1, salt, 4, 5, 4, out); 178 fprintf(stderr, "Out %02X %02X %02X %02X\n", 179 out[0], out[1], out[2], out[3]); 180} 181 182# endif 183 184/* 185 * Now the key derivation function itself. This is a bit evil because it has 186 * to check the ASN1 parameters are valid: and there are quite a few of 187 * them... 188 */ 189 190int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, 191 ASN1_TYPE *param, const EVP_CIPHER *c, 192 const EVP_MD *md, int en_de) 193{ 194 const unsigned char *pbuf; 195 int plen; 196 PBE2PARAM *pbe2 = NULL; 197 const EVP_CIPHER *cipher; 198 199 int rv = 0; 200 201 if (param == NULL || param->type != V_ASN1_SEQUENCE || 202 param->value.sequence == NULL) { 203 EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_DECODE_ERROR); 204 goto err; 205 } 206 207 pbuf = param->value.sequence->data; 208 plen = param->value.sequence->length; 209 if (!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) { 210 EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_DECODE_ERROR); 211 goto err; 212 } 213 214 /* See if we recognise the key derivation function */ 215 216 if (OBJ_obj2nid(pbe2->keyfunc->algorithm) != NID_id_pbkdf2) { 217 EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, 218 EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION); 219 goto err; 220 } 221 222 /* 223 * lets see if we recognise the encryption algorithm. 224 */ 225 226 cipher = EVP_get_cipherbyobj(pbe2->encryption->algorithm); 227 228 if (!cipher) { 229 EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_CIPHER); 230 goto err; 231 } 232 233 /* Fixup cipher based on AlgorithmIdentifier */ 234 if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de)) 235 goto err; 236 if (EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) { 237 EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_CIPHER_PARAMETER_ERROR); 238 goto err; 239 } 240 rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass, passlen, 241 pbe2->keyfunc->parameter, c, md, en_de); 242 err: 243 PBE2PARAM_free(pbe2); 244 return rv; 245} 246 247int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, 248 int passlen, ASN1_TYPE *param, 249 const EVP_CIPHER *c, const EVP_MD *md, int en_de) 250{ 251 unsigned char *salt, key[EVP_MAX_KEY_LENGTH]; 252 const unsigned char *pbuf; 253 int saltlen, iter, plen; 254 int rv = 0; 255 unsigned int keylen = 0; 256 int prf_nid, hmac_md_nid; 257 PBKDF2PARAM *kdf = NULL; 258 const EVP_MD *prfmd; 259 260 if (EVP_CIPHER_CTX_cipher(ctx) == NULL) { 261 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_NO_CIPHER_SET); 262 goto err; 263 } 264 keylen = EVP_CIPHER_CTX_key_length(ctx); 265 OPENSSL_assert(keylen <= sizeof key); 266 267 /* Decode parameter */ 268 269 if (!param || (param->type != V_ASN1_SEQUENCE)) { 270 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR); 271 goto err; 272 } 273 274 pbuf = param->value.sequence->data; 275 plen = param->value.sequence->length; 276 277 if (!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen))) { 278 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR); 279 goto err; 280 } 281 282 keylen = EVP_CIPHER_CTX_key_length(ctx); 283 284 /* Now check the parameters of the kdf */ 285 286 if (kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)) { 287 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_KEYLENGTH); 288 goto err; 289 } 290 291 if (kdf->prf) 292 prf_nid = OBJ_obj2nid(kdf->prf->algorithm); 293 else 294 prf_nid = NID_hmacWithSHA1; 295 296 if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) { 297 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); 298 goto err; 299 } 300 301 prfmd = EVP_get_digestbynid(hmac_md_nid); 302 if (prfmd == NULL) { 303 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); 304 goto err; 305 } 306 307 if (kdf->salt->type != V_ASN1_OCTET_STRING) { 308 EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_SALT_TYPE); 309 goto err; 310 } 311 312 /* it seems that its all OK */ 313 salt = kdf->salt->value.octet_string->data; 314 saltlen = kdf->salt->value.octet_string->length; 315 iter = ASN1_INTEGER_get(kdf->iter); 316 if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd, 317 keylen, key)) 318 goto err; 319 rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de); 320 err: 321 OPENSSL_cleanse(key, keylen); 322 PBKDF2PARAM_free(kdf); 323 return rv; 324} 325 326# ifdef DEBUG_PKCS5V2 327static void h__dump(const unsigned char *p, int len) 328{ 329 for (; len--; p++) 330 fprintf(stderr, "%02X ", *p); 331 fprintf(stderr, "\n"); 332} 333# endif 334#endif 335