~ubuntu-branches/ubuntu/precise/openssl098/precise

« back to all changes in this revision

Viewing changes to crypto/evp/p5_crpt2.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2011-03-23 19:50:31 UTC
  • Revision ID: james.westby@ubuntu.com-20110323195031-6h9crj4bymhhr8b8
Tags: upstream-0.9.8o
ImportĀ upstreamĀ versionĀ 0.9.8o

Show diffs side-by-side

added added

removed removed

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