1 /* $NetBSD: pkcs12.c,v 1.1.1.2 2014/04/24 12:45:30 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * 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 the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <config.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <assert.h> 41 42 #include <pkcs12.h> 43 #include <bn.h> 44 45 #include <krb5/roken.h> 46 47 int 48 PKCS12_key_gen(const void *key, size_t keylen, 49 const void *salt, size_t saltlen, 50 int id, int iteration, size_t outkeysize, 51 void *out, const EVP_MD *md) 52 { 53 unsigned char *v, *I, hash[EVP_MAX_MD_SIZE]; 54 unsigned int size, size_I = 0; 55 unsigned char idc = id; 56 EVP_MD_CTX *ctx; 57 unsigned char *outp = out; 58 int i, vlen; 59 60 /** 61 * The argument key is pointing to an utf16 string, and thus 62 * keylen that is no a multiple of 2 is invalid. 63 */ 64 if (keylen & 1) 65 return 0; 66 67 ctx = EVP_MD_CTX_create(); 68 if (ctx == NULL) 69 return 0; 70 71 vlen = EVP_MD_block_size(md); 72 v = malloc(vlen + 1); 73 if (v == NULL) { 74 EVP_MD_CTX_destroy(ctx); 75 return 0; 76 } 77 78 I = calloc(1, vlen * 2); 79 if (I == NULL) { 80 EVP_MD_CTX_destroy(ctx); 81 free(v); 82 return 0; 83 } 84 85 if (salt && saltlen > 0) { 86 for (i = 0; i < vlen; i++) 87 I[i] = ((unsigned char*)salt)[i % saltlen]; 88 size_I += vlen; 89 } 90 /* 91 * There is a diffrence between the no password string and the 92 * empty string, in the empty string the UTF16 NUL terminator is 93 * included into the string. 94 */ 95 if (key) { 96 for (i = 0; i < vlen / 2; i++) { 97 I[(i * 2) + size_I] = 0; 98 I[(i * 2) + size_I + 1] = ((unsigned char*)key)[i % (keylen + 1)]; 99 } 100 size_I += vlen; 101 } 102 103 while (1) { 104 BIGNUM *bnB, *bnOne; 105 106 if (!EVP_DigestInit_ex(ctx, md, NULL)) { 107 EVP_MD_CTX_destroy(ctx); 108 free(I); 109 free(v); 110 return 0; 111 } 112 for (i = 0; i < vlen; i++) 113 EVP_DigestUpdate(ctx, &idc, 1); 114 EVP_DigestUpdate(ctx, I, size_I); 115 EVP_DigestFinal_ex(ctx, hash, &size); 116 117 for (i = 1; i < iteration; i++) 118 EVP_Digest(hash, size, hash, &size, md, NULL); 119 120 memcpy(outp, hash, min(outkeysize, size)); 121 if (outkeysize < size) 122 break; 123 outkeysize -= size; 124 outp += size; 125 126 for (i = 0; i < vlen; i++) 127 v[i] = hash[i % size]; 128 129 bnB = BN_bin2bn(v, vlen, NULL); 130 bnOne = BN_new(); 131 BN_set_word(bnOne, 1); 132 133 BN_uadd(bnB, bnB, bnOne); 134 135 for (i = 0; i < vlen * 2; i += vlen) { 136 BIGNUM *bnI; 137 int j; 138 139 bnI = BN_bin2bn(I + i, vlen, NULL); 140 141 BN_uadd(bnI, bnI, bnB); 142 143 j = BN_num_bytes(bnI); 144 if (j > vlen) { 145 assert(j == vlen + 1); 146 BN_bn2bin(bnI, v); 147 memcpy(I + i, v + 1, vlen); 148 } else { 149 memset(I + i, 0, vlen - j); 150 BN_bn2bin(bnI, I + i + vlen - j); 151 } 152 BN_free(bnI); 153 } 154 BN_free(bnB); 155 BN_free(bnOne); 156 size_I = vlen * 2; 157 } 158 159 EVP_MD_CTX_destroy(ctx); 160 free(I); 161 free(v); 162 163 return 1; 164 } 165