p12_key.c revision 296341
1/* p12_key.c */
2/*
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4 * 1999.
5 */
6/* ====================================================================
7 * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 *    software must display the following acknowledgment:
23 *    "This product includes software developed by the OpenSSL Project
24 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 *    endorse or promote products derived from this software without
28 *    prior written permission. For written permission, please contact
29 *    licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 *    nor may "OpenSSL" appear in their names without prior written
33 *    permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 *    acknowledgment:
37 *    "This product includes software developed by the OpenSSL Project
38 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com).  This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60#include <stdio.h>
61#include "cryptlib.h"
62#include <openssl/pkcs12.h>
63#include <openssl/bn.h>
64
65/* Uncomment out this line to get debugging info about key generation */
66/*
67 * #define DEBUG_KEYGEN
68 */
69#ifdef DEBUG_KEYGEN
70# include <openssl/bio.h>
71extern BIO *bio_err;
72void h__dump(unsigned char *p, int len);
73#endif
74
75/* PKCS12 compatible key/IV generation */
76#ifndef min
77# define min(a,b) ((a) < (b) ? (a) : (b))
78#endif
79
80int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt,
81                       int saltlen, int id, int iter, int n,
82                       unsigned char *out, const EVP_MD *md_type)
83{
84    int ret;
85    unsigned char *unipass;
86    int uniplen;
87
88    if (!pass) {
89        unipass = NULL;
90        uniplen = 0;
91    } else if (!OPENSSL_asc2uni(pass, passlen, &unipass, &uniplen)) {
92        PKCS12err(PKCS12_F_PKCS12_KEY_GEN_ASC, ERR_R_MALLOC_FAILURE);
93        return 0;
94    }
95    ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen,
96                             id, iter, n, out, md_type);
97    if (ret <= 0)
98        return 0;
99    if (unipass) {
100        OPENSSL_cleanse(unipass, uniplen); /* Clear password from memory */
101        OPENSSL_free(unipass);
102    }
103    return ret;
104}
105
106int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
107                       int saltlen, int id, int iter, int n,
108                       unsigned char *out, const EVP_MD *md_type)
109{
110    unsigned char *B, *D, *I, *p, *Ai;
111    int Slen, Plen, Ilen, Ijlen;
112    int i, j, u, v;
113    int ret = 0;
114    BIGNUM *Ij, *Bpl1;          /* These hold Ij and B + 1 */
115    EVP_MD_CTX ctx;
116#ifdef  DEBUG_KEYGEN
117    unsigned char *tmpout = out;
118    int tmpn = n;
119#endif
120
121#if 0
122    if (!pass) {
123        PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_PASSED_NULL_PARAMETER);
124        return 0;
125    }
126#endif
127
128    EVP_MD_CTX_init(&ctx);
129#ifdef  DEBUG_KEYGEN
130    fprintf(stderr, "KEYGEN DEBUG\n");
131    fprintf(stderr, "ID %d, ITER %d\n", id, iter);
132    fprintf(stderr, "Password (length %d):\n", passlen);
133    h__dump(pass, passlen);
134    fprintf(stderr, "Salt (length %d):\n", saltlen);
135    h__dump(salt, saltlen);
136#endif
137    v = EVP_MD_block_size(md_type);
138    u = EVP_MD_size(md_type);
139    if (u < 0)
140        return 0;
141    D = OPENSSL_malloc(v);
142    Ai = OPENSSL_malloc(u);
143    B = OPENSSL_malloc(v + 1);
144    Slen = v * ((saltlen + v - 1) / v);
145    if (passlen)
146        Plen = v * ((passlen + v - 1) / v);
147    else
148        Plen = 0;
149    Ilen = Slen + Plen;
150    I = OPENSSL_malloc(Ilen);
151    Ij = BN_new();
152    Bpl1 = BN_new();
153    if (!D || !Ai || !B || !I || !Ij || !Bpl1)
154        goto err;
155    for (i = 0; i < v; i++)
156        D[i] = id;
157    p = I;
158    for (i = 0; i < Slen; i++)
159        *p++ = salt[i % saltlen];
160    for (i = 0; i < Plen; i++)
161        *p++ = pass[i % passlen];
162    for (;;) {
163        if (!EVP_DigestInit_ex(&ctx, md_type, NULL)
164            || !EVP_DigestUpdate(&ctx, D, v)
165            || !EVP_DigestUpdate(&ctx, I, Ilen)
166            || !EVP_DigestFinal_ex(&ctx, Ai, NULL))
167            goto err;
168        for (j = 1; j < iter; j++) {
169            if (!EVP_DigestInit_ex(&ctx, md_type, NULL)
170                || !EVP_DigestUpdate(&ctx, Ai, u)
171                || !EVP_DigestFinal_ex(&ctx, Ai, NULL))
172                goto err;
173        }
174        memcpy(out, Ai, min(n, u));
175        if (u >= n) {
176#ifdef DEBUG_KEYGEN
177            fprintf(stderr, "Output KEY (length %d)\n", tmpn);
178            h__dump(tmpout, tmpn);
179#endif
180            ret = 1;
181            goto end;
182        }
183        n -= u;
184        out += u;
185        for (j = 0; j < v; j++)
186            B[j] = Ai[j % u];
187        /* Work out B + 1 first then can use B as tmp space */
188        if (!BN_bin2bn(B, v, Bpl1))
189            goto err;
190        if (!BN_add_word(Bpl1, 1))
191            goto err;
192        for (j = 0; j < Ilen; j += v) {
193            if (!BN_bin2bn(I + j, v, Ij))
194                goto err;
195            if (!BN_add(Ij, Ij, Bpl1))
196                goto err;
197            if (!BN_bn2bin(Ij, B))
198                goto err;
199            Ijlen = BN_num_bytes(Ij);
200            /* If more than 2^(v*8) - 1 cut off MSB */
201            if (Ijlen > v) {
202                if (!BN_bn2bin(Ij, B))
203                    goto err;
204                memcpy(I + j, B + 1, v);
205#ifndef PKCS12_BROKEN_KEYGEN
206                /* If less than v bytes pad with zeroes */
207            } else if (Ijlen < v) {
208                memset(I + j, 0, v - Ijlen);
209                if (!BN_bn2bin(Ij, I + j + v - Ijlen))
210                    goto err;
211#endif
212            } else if (!BN_bn2bin(Ij, I + j))
213                goto err;
214        }
215    }
216
217 err:
218    PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE);
219
220 end:
221    OPENSSL_free(Ai);
222    OPENSSL_free(B);
223    OPENSSL_free(D);
224    OPENSSL_free(I);
225    BN_free(Ij);
226    BN_free(Bpl1);
227    EVP_MD_CTX_cleanup(&ctx);
228    return ret;
229}
230
231#ifdef DEBUG_KEYGEN
232void h__dump(unsigned char *p, int len)
233{
234    for (; len--; p++)
235        fprintf(stderr, "%02X", *p);
236    fprintf(stderr, "\n");
237}
238#endif
239