1 /* pvkwrite.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3 * project 2000.
4 */
5 /* ====================================================================
6 * Copyright (c) 2000 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
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <openssl/pem.h>
63 #include <openssl/rand.h>
64 #include <openssl/err.h>
65 #include "pvk.h"
66
write_word(BIO * out,unsigned short dat)67 static int write_word(BIO *out, unsigned short dat)
68 {
69 unsigned char buf[2];
70 buf[0] = dat & 0xff;
71 buf[1] = (dat >> 8) & 0xff;
72 if (BIO_write(out, buf, 2) != 2) return 0;
73 return 1;
74 }
75
write_dword(BIO * out,uint32_t dat)76 static int write_dword(BIO *out, uint32_t dat)
77 {
78 unsigned char buf[4];
79 buf[0] = dat & 0xff;
80 buf[1] = (dat >> 8) & 0xff;
81 buf[2] = (dat >> 16) & 0xff;
82 buf[3] = (dat >> 24) & 0xff;
83 if (BIO_write(out, buf, 4) != 4) return 0;
84 return 1;
85 }
86
put_dword(unsigned char ** p,uint32_t dat)87 static void put_dword(unsigned char **p, uint32_t dat)
88 {
89 unsigned char *buf;
90 buf = *p;
91 buf[0] = dat & 0xff;
92 buf[1] = (dat >> 8) & 0xff;
93 buf[2] = (dat >> 16) & 0xff;
94 buf[3] = (dat >> 24) & 0xff;
95 *p += 4;
96 }
97
pvk_write(BIO * out,PVK_DAT * pvk)98 int pvk_write(BIO *out, PVK_DAT *pvk)
99 {
100 int keylen;
101 if( !write_dword(out, pvk->magic) ||
102 !write_dword(out, pvk->res) ||
103 !write_dword(out, pvk->keytype) ||
104 !write_dword(out, pvk->crypt) ||
105 !write_dword(out, pvk->saltlen) ||
106 !write_dword(out, pvk->keylen) ) goto err;
107 if (pvk->saltlen)
108 if(BIO_write(out, pvk->salt, pvk->saltlen) != pvk->saltlen)
109 goto err;
110 if(BIO_write(out, &pvk->btype, 1) != 1) goto err;
111 if(BIO_write(out, &pvk->version, 1) != 1) goto err;
112 if(!write_word(out, pvk->reserved)) goto err;
113 if(!write_dword(out, pvk->keyalg)) goto err;
114
115 if (pvk->keylen > 8) {
116 keylen = pvk->keylen - 8;
117 if(BIO_write(out, pvk->key, keylen) != keylen) goto err;
118 }
119 return 1;
120
121 err:
122 PVKerr(PVK_F_PVK_WRITE,PVK_R_FILE_WRITE_ERROR);
123 return 0;
124 }
125
pvk_encrypt(PVK_DAT * pvk,char * pass,int encr)126 int pvk_encrypt(PVK_DAT *pvk, char *pass, int encr)
127 {
128 EVP_MD_CTX *ctx;
129 EVP_CIPHER_CTX *cctx;
130 unsigned char *buf;
131 unsigned char tmpkey[EVP_MAX_KEY_LENGTH];
132 int outlen;
133 pvk->saltlen = PVK_SALTLEN;
134 RAND_seed(pass, strlen(pass));
135 if(!(pvk->salt = OPENSSL_malloc(pvk->saltlen))) {
136 PVKerr(PVK_F_PVK_ENCRYPT,ERR_R_MALLOC_FAILURE);
137 return 0;
138 }
139 RAND_bytes(pvk->salt, pvk->saltlen);
140 if(!(buf = OPENSSL_malloc(pvk->keylen + 8))) {
141 PVKerr(PVK_F_PVK_ENCRYPT,ERR_R_MALLOC_FAILURE);
142 return 0;
143 }
144 ctx = EVP_MD_CTX_new();
145 EVP_DigestInit(ctx, EVP_sha1());
146 EVP_DigestUpdate(ctx, pvk->salt, pvk->saltlen);
147 EVP_DigestUpdate(ctx, pass, strlen(pass));
148 EVP_DigestFinal(ctx, tmpkey, NULL);
149 EVP_MD_CTX_free(ctx);
150
151 if(encr == PVK_WEAK) memset(tmpkey + 5, 0, 11);
152
153 cctx = EVP_CIPHER_CTX_new();
154 EVP_EncryptInit(cctx, EVP_rc4(), tmpkey, NULL);
155 EVP_EncryptUpdate(cctx, buf, &outlen, pvk->key, pvk->keylen);
156 /* Not needed but do it to cleanup */
157 EVP_EncryptFinal(cctx, buf + outlen, &outlen);
158 EVP_CIPHER_CTX_free(cctx);
159 OPENSSL_free(pvk->key);
160 pvk->key = buf;
161 pvk->crypt = 1;
162 pvk->encr = encr;
163 memset(tmpkey, 0, EVP_MAX_KEY_LENGTH);
164 return 1;
165 }
166
167 /* Convert bignum to little endian format */
BN2lend(const BIGNUM * num,unsigned char * p)168 static int BN2lend (const BIGNUM *num, unsigned char *p)
169 {
170 int nbyte, i;
171 unsigned char c;
172 nbyte = BN_num_bytes(num);
173 BN_bn2bin (num, p);
174 /* Inplace byte reversal */
175 for (i = 0; i < nbyte / 2; i++) {
176 c = p[i];
177 p[i] = p[nbyte - i - 1];
178 p[nbyte - i - 1] = c;
179 }
180 return 1;
181 }
182
183 /* Convert RSA key into PVK structure */
184
rsa2pvk(RSA * rsa,PVK_DAT * pvk,uint32_t alg)185 int rsa2pvk(RSA *rsa, PVK_DAT *pvk, uint32_t alg)
186 {
187 int numbytes;
188 unsigned char *p;
189
190 /* Initialise structure */
191 pvk->magic = PVK_MAGIC;
192
193 pvk->res = 0;
194 pvk->crypt = 0;
195 pvk->btype = PKEYBLOB;
196 pvk->version = 2;
197 pvk->reserved = 0;
198 pvk->saltlen = 0;
199 pvk->salt = NULL;
200 pvk->encr = PVK_NONE;
201
202 if(alg == -1) pvk->keyalg = RSA_SIG;
203 else pvk->keyalg = alg;
204
205 if(pvk->keyalg == RSA_KEYX) pvk->keytype = PVK_KEYX;
206 else if(pvk->keyalg == RSA_SIG) pvk->keytype = PVK_SIG;
207
208 /* Set up a private key blob */
209 numbytes = BN_num_bytes (RSA_get0_n(rsa));
210 /* Allocate enough room for blob */
211 if (!(pvk->key = calloc(1, 12 + numbytes * 5))) {
212 PVKerr(PVK_F_RSA2PVK,ERR_R_MALLOC_FAILURE);
213 return 0;
214 }
215
216 p = pvk->key;
217
218 memcpy(p, "RSA2", 4);
219
220 p+= 4;
221
222 put_dword(&p, numbytes << 3); /* Number of bits */
223 put_dword(&p, BN_get_word(RSA_get0_e(rsa))); /* Public exponent */
224
225 /* Convert each element */
226
227 BN2lend (RSA_get0_n(rsa), p);
228 p += numbytes;
229 BN2lend (RSA_get0_p(rsa), p);
230 p += numbytes/2;
231 BN2lend (RSA_get0_q(rsa), p);
232 p += numbytes/2;
233 BN2lend (RSA_get0_dmp1(rsa), p);
234 p += numbytes/2;
235 BN2lend (RSA_get0_dmq1(rsa), p);
236 p += numbytes/2;
237 BN2lend (RSA_get0_iqmp(rsa), p);
238 p += numbytes/2;
239 BN2lend (RSA_get0_d(rsa), p);
240 p += numbytes;
241 pvk->keylen = p - pvk->key + 8;
242 RAND_seed(pvk->key, pvk->keylen);
243 return 1;
244 }
245