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