1f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/*
2f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
3f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * keyfiles.
4f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
5f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The horribleness of the code is probably mine (matt).
6f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
7f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Modifications copyright 2003 Matt Johnston
8f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
9f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * PuTTY is copyright 1997-2003 Simon Tatham.
10f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
11f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
12f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
13f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Justin Bradford, and CORE SDI S.A.
14f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
15f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Permission is hereby granted, free of charge, to any person
16f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * obtaining a copy of this software and associated documentation files
17f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * (the "Software"), to deal in the Software without restriction,
18f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * including without limitation the rights to use, copy, modify, merge,
19f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * publish, distribute, sublicense, and/or sell copies of the Software,
20f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * and to permit persons to whom the Software is furnished to do so,
21f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * subject to the following conditions:
22f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
23f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The above copyright notice and this permission notice shall be
24f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * included in all copies or substantial portions of the Software.
25f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
26f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * NONINFRINGEMENT.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
30f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
31f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
34f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
35f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#include "keyimport.h"
36f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#include "bignum.h"
37f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#include "buffer.h"
38f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#include "dbutil.h"
39f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
40f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define PUT_32BIT(cp, value) do { \
41f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project  (cp)[3] = (unsigned char)(value); \
42f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project  (cp)[2] = (unsigned char)((value) >> 8); \
43f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project  (cp)[1] = (unsigned char)((value) >> 16); \
44f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project  (cp)[0] = (unsigned char)((value) >> 24); } while (0)
45f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
46f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define GET_32BIT(cp) \
47f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	(((unsigned long)(unsigned char)(cp)[0] << 24) | \
48f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	((unsigned long)(unsigned char)(cp)[1] << 16) | \
49f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	((unsigned long)(unsigned char)(cp)[2] << 8) | \
50f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	((unsigned long)(unsigned char)(cp)[3]))
51f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
52f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int openssh_encrypted(const char *filename);
53f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic sign_key *openssh_read(const char *filename, char *passphrase);
54f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int openssh_write(const char *filename, sign_key *key,
55f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				  char *passphrase);
56f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
57f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int dropbear_write(const char*filename, sign_key * key);
58f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic sign_key *dropbear_read(const char* filename);
59f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
60f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
61f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int sshcom_encrypted(const char *filename, char **comment);
62f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase);
63f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int sshcom_write(const char *filename, struct ssh2_userkey *key,
64f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				 char *passphrase);
65f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
66f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
67f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectint import_encrypted(const char* filename, int filetype) {
68f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
69f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (filetype == KEYFILE_OPENSSH) {
70f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return openssh_encrypted(filename);
71f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
72f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (filetype == KEYFILE_SSHCOM) {
73f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return sshcom_encrypted(filename, NULL);
74f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
75f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
76f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return 0;
77f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
78f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
79f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectsign_key *import_read(const char *filename, char *passphrase, int filetype) {
80f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
81f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (filetype == KEYFILE_OPENSSH) {
82f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return openssh_read(filename, passphrase);
83f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (filetype == KEYFILE_DROPBEAR) {
84f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return dropbear_read(filename);
85f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
86f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (filetype == KEYFILE_SSHCOM) {
87f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return sshcom_read(filename, passphrase);
88f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
89f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
90f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return NULL;
91f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
92f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
93f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectint import_write(const char *filename, sign_key *key, char *passphrase,
94f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int filetype) {
95f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
96f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (filetype == KEYFILE_OPENSSH) {
97f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return openssh_write(filename, key, passphrase);
98f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (filetype == KEYFILE_DROPBEAR) {
99f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return dropbear_write(filename, key);
100f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
101f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (filetype == KEYFILE_SSHCOM) {
102f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return sshcom_write(filename, key, passphrase);
103f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
104f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
105f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return 0;
106f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
107f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
108f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic sign_key *dropbear_read(const char* filename) {
109f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
110f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buffer * buf = NULL;
111f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	sign_key *ret = NULL;
112f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int type;
113f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
114f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf = buf_new(MAX_PRIVKEY_SIZE);
115f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
116f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
117f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
118f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
119f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_setpos(buf, 0);
120f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = new_sign_key();
121f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
122f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	type = DROPBEAR_SIGNKEY_ANY;
123f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (buf_get_priv_key(buf, ret, &type) == DROPBEAR_FAILURE){
124f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
125f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
126f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_free(buf);
127f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
128f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
129f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
130f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projecterror:
131f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (buf) {
132f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_free(buf);
133f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
134f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret) {
135f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		sign_key_free(ret);
136f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
137f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return NULL;
138f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
139f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
140f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* returns 0 on fail, 1 on success */
141f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int dropbear_write(const char*filename, sign_key * key) {
142f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
143f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int keytype = -1;
144f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buffer * buf;
145f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	FILE*fp;
146f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int len;
147f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int ret;
148f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
149f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_RSA
150f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->rsakey != NULL) {
151f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		keytype = DROPBEAR_SIGNKEY_RSA;
152f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
153f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
154f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_DSS
155f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->dsskey != NULL) {
156f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		keytype = DROPBEAR_SIGNKEY_DSS;
157f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
158f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
159f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
160f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf = buf_new(MAX_PRIVKEY_SIZE);
161f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_put_priv_key(buf, key, keytype);
162f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
163f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fp = fopen(filename, "w");
164f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fp) {
165f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret = 0;
166f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto out;
167f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
168f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
169f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_setpos(buf, 0);
170f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	do {
171f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len = fwrite(buf_getptr(buf, buf->len - buf->pos),
172f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				1, buf->len - buf->pos, fp);
173f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(buf, len);
174f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} while (len > 0 && buf->len != buf->pos);
175f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
176f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fclose(fp);
177f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
178f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (buf->pos != buf->len) {
179f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret = 0;
180f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
181f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret = 1;
182f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
183f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectout:
184f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_free(buf);
185f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
186f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
187f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
188f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
189f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* ----------------------------------------------------------------------
190f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Helper routines. (The base64 ones are defined in sshpubk.c.)
191f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
192f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
193f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define isbase64(c) (	((c) >= 'A' && (c) <= 'Z') || \
194f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						 ((c) >= 'a' && (c) <= 'z') || \
195f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						 ((c) >= '0' && (c) <= '9') || \
196f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						 (c) == '+' || (c) == '/' || (c) == '=' \
197f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						 )
198f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
199f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* cpl has to be less than 100 */
200f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic void base64_encode_fp(FILE * fp, unsigned char *data,
201f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int datalen, int cpl)
202f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
203f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project    char out[100];
204f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project    int n;
205f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned long outlen;
206f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int rawcpl;
207f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	rawcpl = cpl * 3 / 4;
208f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert((unsigned int)cpl < sizeof(out));
209f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
210f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project    while (datalen > 0) {
211f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		n = (datalen < rawcpl ? datalen : rawcpl);
212f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		outlen = sizeof(out);
213f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		base64_encode(data, n, out, &outlen);
214f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		data += n;
215f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		datalen -= n;
216f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fwrite(out, 1, outlen, fp);
217f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fputc('\n', fp);
218f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project    }
219f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
220f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/*
221f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Read an ASN.1/BER identifier and length pair.
222f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
223f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Flags are a combination of the #defines listed below.
224f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
225f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Returns -1 if unsuccessful; otherwise returns the number of
226f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * bytes used out of the source data.
227f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
228f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
229f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* ASN.1 tag classes. */
230f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CLASS_UNIVERSAL		(0 << 6)
231f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CLASS_APPLICATION	  (1 << 6)
232f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
233f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CLASS_PRIVATE		  (3 << 6)
234f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CLASS_MASK			 (3 << 6)
235f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
236f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* Primitive versus constructed bit. */
237f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define ASN1_CONSTRUCTED			(1 << 5)
238f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
239f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int ber_read_id_len(void *source, int sourcelen,
240f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						   int *id, int *length, int *flags)
241f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
242f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *p = (unsigned char *) source;
243f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
244f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (sourcelen == 0)
245f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return -1;
246f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
247f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	*flags = (*p & 0xE0);
248f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if ((*p & 0x1F) == 0x1F) {
249f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		*id = 0;
250f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while (*p & 0x80) {
251f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			*id = (*id << 7) | (*p & 0x7F);
252f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			p++, sourcelen--;
253f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (sourcelen == 0)
254f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				return -1;
255f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
256f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		*id = (*id << 7) | (*p & 0x7F);
257f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p++, sourcelen--;
258f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
259f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		*id = *p & 0x1F;
260f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p++, sourcelen--;
261f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
262f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
263f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (sourcelen == 0)
264f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return -1;
265f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
266f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (*p & 0x80) {
267f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int n = *p & 0x7F;
268f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p++, sourcelen--;
269f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (sourcelen < n)
270f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			return -1;
271f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		*length = 0;
272f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while (n--)
273f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			*length = (*length << 8) | (*p++);
274f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		sourcelen -= n;
275f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
276f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		*length = *p;
277f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p++, sourcelen--;
278f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
279f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
280f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return p - (unsigned char *) source;
281f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
282f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
283f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/*
284f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Write an ASN.1/BER identifier and length pair. Returns the
285f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * number of bytes consumed. Assumes dest contains enough space.
286f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Will avoid writing anything if dest is NULL, but still return
287f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * amount of space required.
288f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
289f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int ber_write_id_len(void *dest, int id, int length, int flags)
290f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
291f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *d = (unsigned char *)dest;
292f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int len = 0;
293f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
294f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (id <= 30) {
295f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
296f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Identifier is one byte.
297f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
298f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len++;
299f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (d) *d++ = id | flags;
300f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
301f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int n;
302f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
303f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Identifier is multiple bytes: the first byte is 11111
304f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * plus the flags, and subsequent bytes encode the value of
305f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * the identifier, 7 bits at a time, with the top bit of
306f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * each byte 1 except the last one which is 0.
307f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
308f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len++;
309f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (d) *d++ = 0x1F | flags;
310f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		for (n = 1; (id >> (7*n)) > 0; n++)
311f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			continue;					   /* count the bytes */
312f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while (n--) {
313f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			len++;
314f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F);
315f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
316f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
317f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
318f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (length < 128) {
319f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
320f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Length is one byte.
321f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
322f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len++;
323f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (d) *d++ = length;
324f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
325f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int n;
326f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
327f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Length is multiple bytes. The first is 0x80 plus the
328f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * number of subsequent bytes, and the subsequent bytes
329f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * encode the actual length.
330f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
331f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		for (n = 1; (length >> (8*n)) > 0; n++)
332f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			continue;					   /* count the bytes */
333f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len++;
334f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (d) *d++ = 0x80 | n;
335f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while (n--) {
336f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			len++;
337f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (d) *d++ = (length >> (8*n)) & 0xFF;
338f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
339f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
340f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
341f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return len;
342f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
343f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
344f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
345f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* Simple structure to point to an mp-int within a blob. */
346f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstruct mpint_pos { void *start; int bytes; };
347f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
348f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* ----------------------------------------------------------------------
349f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Code to read and write OpenSSH private keys.
350f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
351f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
352f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectenum { OSSH_DSA, OSSH_RSA };
353f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstruct openssh_key {
354f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int type;
355f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int encrypted;
356f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char iv[32];
357f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *keyblob;
358f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned int keyblob_len, keyblob_size;
359f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project};
360f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
361f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic struct openssh_key *load_openssh_key(const char *filename)
362f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
363f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct openssh_key *ret;
364f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	FILE *fp = NULL;
365f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char buffer[256];
366f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *errmsg = NULL, *p = NULL;
367f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int headers_done;
368f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned long len, outlen;
369f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
370f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
371f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->keyblob = NULL;
372f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->keyblob_len = ret->keyblob_size = 0;
373f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->encrypted = 0;
374f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(ret->iv, 0, sizeof(ret->iv));
375f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
376f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (strlen(filename) == 1 && filename[0] == '-') {
377f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fp = stdin;
378f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
379f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fp = fopen(filename, "r");
380f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
381f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fp) {
382f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Unable to open key file";
383f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
384f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
385f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fgets(buffer, sizeof(buffer), fp) ||
386f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		0 != strncmp(buffer, "-----BEGIN ", 11) ||
387f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
388f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "File does not begin with OpenSSH key header";
389f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
390f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
391f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
392f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret->type = OSSH_RSA;
393f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
394f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret->type = OSSH_DSA;
395f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	else {
396f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Unrecognised key type";
397f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
398f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
399f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
400f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	headers_done = 0;
401f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	while (1) {
402f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!fgets(buffer, sizeof(buffer), fp)) {
403f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "Unexpected end of file";
404f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
405f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
406f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (0 == strncmp(buffer, "-----END ", 9) &&
407f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
408f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			break;					   /* done */
409f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if ((p = strchr(buffer, ':')) != NULL) {
410f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (headers_done) {
411f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				errmsg = "Header found in body of key data";
412f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				goto error;
413f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
414f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			*p++ = '\0';
415f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			while (*p && isspace((unsigned char)*p)) p++;
416f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (!strcmp(buffer, "Proc-Type")) {
417f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (p[0] != '4' || p[1] != ',') {
418f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					errmsg = "Proc-Type is not 4 (only 4 is supported)";
419f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					goto error;
420f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
421f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				p += 2;
422f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (!strcmp(p, "ENCRYPTED\n"))
423f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					ret->encrypted = 1;
424f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			} else if (!strcmp(buffer, "DEK-Info")) {
425f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				int i, j;
426f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
427f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (strncmp(p, "DES-EDE3-CBC,", 13)) {
428f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					errmsg = "Ciphers other than DES-EDE3-CBC not supported";
429f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					goto error;
430f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
431f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				p += 13;
432f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				for (i = 0; i < 8; i++) {
433f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					if (1 != sscanf(p, "%2x", &j))
434f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						break;
435f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					ret->iv[i] = j;
436f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					p += 2;
437f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
438f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (i < 8) {
439f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					errmsg = "Expected 16-digit iv in DEK-Info";
440f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					goto error;
441f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
442f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
443f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		} else {
444f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			headers_done = 1;
445f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			len = strlen(buffer);
446f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			outlen = len*4/3;
447f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (ret->keyblob_len + outlen > ret->keyblob_size) {
448f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				ret->keyblob_size = ret->keyblob_len + outlen + 256;
449f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				ret->keyblob = (unsigned char*)m_realloc(ret->keyblob,
450f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						ret->keyblob_size);
451f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
452f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			outlen = ret->keyblob_size - ret->keyblob_len;
453f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (base64_decode(buffer, len,
454f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
455f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				errmsg = "Error decoding base64";
456f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				goto error;
457f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
458f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			ret->keyblob_len += outlen;
459f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
460f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
461f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
462f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret->keyblob_len == 0 || !ret->keyblob) {
463f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key body not present";
464f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
465f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
466f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
467f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret->encrypted && ret->keyblob_len % 8 != 0) {
468f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Encrypted key blob is not a multiple of cipher block size";
469f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
470f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
471f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
472f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(buffer, 0, sizeof(buffer));
473f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
474f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
475f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
476f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(buffer, 0, sizeof(buffer));
477f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret) {
478f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (ret->keyblob) {
479f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			memset(ret->keyblob, 0, ret->keyblob_size);
480f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			m_free(ret->keyblob);
481f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
482f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(&ret, 0, sizeof(ret));
483f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(ret);
484f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
485f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (fp) {
486f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fclose(fp);
487f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
488f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (errmsg) {
489f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fprintf(stderr, "Error: %s\n", errmsg);
490f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
491f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return NULL;
492f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
493f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
494f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int openssh_encrypted(const char *filename)
495f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
496f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct openssh_key *key = load_openssh_key(filename);
497f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int ret;
498f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
499f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!key)
500f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return 0;
501f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = key->encrypted;
502f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(key->keyblob, 0, key->keyblob_size);
503f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key->keyblob);
504f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(&key, 0, sizeof(key));
505f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key);
506f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
507f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
508f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
509f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic sign_key *openssh_read(const char *filename, char *passphrase)
510f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
511f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct openssh_key *key;
512f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *p;
513f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int ret, id, len, flags;
514f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int i, num_integers = 0;
515f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	sign_key *retval = NULL;
516f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *errmsg;
517f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *modptr = NULL;
518f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int modlen = -9999;
519f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int type;
520f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
521f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	sign_key *retkey;
522f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buffer * blobbuf = NULL;
523f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
524f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	key = load_openssh_key(filename);
525f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
526f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!key)
527f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return NULL;
528f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
529f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->encrypted) {
530f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "encrypted keys not supported currently";
531f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
532f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
533f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* matt TODO */
534f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
535f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Derive encryption key from passphrase and iv/salt:
536f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *
537f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block A equal MD5(passphrase || iv)
538f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block B equal MD5(A || passphrase || iv)
539f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - block C would be MD5(B || passphrase || iv) and so on
540f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - encryption key is the first N bytes of A || B
541f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
542f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct MD5Context md5c;
543f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		unsigned char keybuf[32];
544f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
545f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
546f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
547f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)key->iv, 8);
548f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf, &md5c);
549f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
550f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
551f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, keybuf, 16);
552f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
553f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)key->iv, 8);
554f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf+16, &md5c);
555f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
556f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
557f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Now decrypt the key blob.
558f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
559f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
560f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project								 key->keyblob, key->keyblob_len);
561f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
562f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(&md5c, 0, sizeof(md5c));
563f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(keybuf, 0, sizeof(keybuf));
564f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
565f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
566f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
567f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
568f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Now we have a decrypted key blob, which contains an ASN.1
569f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * encoded private key. We must now untangle the ASN.1.
570f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *
571f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * We expect the whole key blob to be formatted as a SEQUENCE
572f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * (0x30 followed by a length code indicating that the rest of
573f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * the blob is part of the sequence). Within that SEQUENCE we
574f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * expect to see a bunch of INTEGERs. What those integers mean
575f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * depends on the key type:
576f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *
577f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *  - For RSA, we expect the integers to be 0, n, e, d, p, q,
578f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *	dmp1, dmq1, iqmp in that order. (The last three are d mod
579f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *	(p-1), d mod (q-1), inverse of q mod p respectively.)
580f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *
581f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *  - For DSA, we expect them to be 0, p, q, g, y, x in that
582f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *	order.
583f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
584f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
585f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	p = key->keyblob;
586f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
587f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
588f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
589f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	p += ret;
590f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret < 0 || id != 16) {
591f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "ASN.1 decoding failure - wrong password?";
592f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
593f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
594f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
595f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Expect a load of INTEGERs. */
596f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->type == OSSH_RSA)
597f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		num_integers = 9;
598f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	else if (key->type == OSSH_DSA)
599f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		num_integers = 6;
600f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
601f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
602f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Space to create key blob in.
603f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
604f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	blobbuf = buf_new(3000);
605f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
606f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->type == OSSH_DSA) {
607f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_putstring(blobbuf, "ssh-dss", 7);
608f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (key->type == OSSH_RSA) {
609f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_putstring(blobbuf, "ssh-rsa", 7);
610f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
611f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
612f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	for (i = 0; i < num_integers; i++) {
613f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
614f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project							  &id, &len, &flags);
615f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p += ret;
616f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (ret < 0 || id != 2 ||
617f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			key->keyblob+key->keyblob_len-p < len) {
618f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "ASN.1 decoding failure";
619f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
620f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
621f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
622f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (i == 0) {
623f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			/*
624f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * The first integer should be zero always (I think
625f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * this is some sort of version indication).
626f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 */
627f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (len != 1 || p[0] != 0) {
628f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				errmsg = "Version number mismatch";
629f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				goto error;
630f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
631f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		} else if (key->type == OSSH_RSA) {
632f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			/*
633f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * OpenSSH key order is n, e, d, p, q, dmp1, dmq1, iqmp
634f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * but we want e, n, d, p, q
635f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 */
636f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (i == 1) {
637f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				/* Save the details for after we deal with number 2. */
638f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				modptr = (char *)p;
639f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				modlen = len;
640f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			} else if (i >= 2 && i <= 5) {
641f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				buf_putstring(blobbuf, p, len);
642f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (i == 2) {
643f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					buf_putstring(blobbuf, modptr, modlen);
644f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
645f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
646f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		} else if (key->type == OSSH_DSA) {
647f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			/*
648f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * OpenSSH key order is p, q, g, y, x,
649f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * we want the same.
650f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 */
651f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			buf_putstring(blobbuf, p, len);
652f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
653f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
654f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* Skip past the number. */
655f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		p += len;
656f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
657f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
658f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
659f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Now put together the actual key. Simplest way to do this is
660f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * to assemble our own key blobs and feed them to the createkey
661f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * functions; this is a bit faffy but it does mean we get all
662f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * the sanity checks for free.
663f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
664f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retkey = new_sign_key();
665f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_setpos(blobbuf, 0);
666f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	type = DROPBEAR_SIGNKEY_ANY;
667f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (buf_get_priv_key(blobbuf, retkey, &type)
668f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			!= DROPBEAR_SUCCESS) {
669f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "unable to create key structure";
670f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		sign_key_free(retkey);
671f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		retkey = NULL;
672f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
673f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
674f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
675f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	errmsg = NULL;					 /* no error */
676f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retval = retkey;
677f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
678f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
679f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (blobbuf) {
680f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_burn(blobbuf);
681f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_free(blobbuf);
682f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
683f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_burn(key->keyblob, key->keyblob_size);
684f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key->keyblob);
685f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_burn(key, sizeof(key));
686f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key);
687f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (errmsg) {
688f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fprintf(stderr, "Error: %s\n", errmsg);
689f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
690f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return retval;
691f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
692f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
693f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int openssh_write(const char *filename, sign_key *key,
694f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				  char *passphrase)
695f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
696f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buffer * keyblob = NULL;
697f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buffer * extrablob = NULL; /* used for calculated values to write */
698f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *outblob = NULL;
699f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int outlen = -9999;
700f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct mpint_pos numbers[9];
701f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int nnumbers = -1, pos, len, seqlen, i;
702f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *header = NULL, *footer = NULL;
703f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char zero[1];
704f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char iv[8];
705f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int ret = 0;
706f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	FILE *fp;
707f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int keytype = -1;
708f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
709f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_RSA
710f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
711f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
712f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->rsakey != NULL) {
713f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		keytype = DROPBEAR_SIGNKEY_RSA;
714f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
715f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
716f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_DSS
717f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->dsskey != NULL) {
718f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		keytype = DROPBEAR_SIGNKEY_DSS;
719f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
720f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif
721f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
722f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert(keytype != -1);
723f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
724f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
725f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Fetch the key blobs.
726f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
727f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	keyblob = buf_new(3000);
728f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_put_priv_key(keyblob, key, keytype);
729f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
730f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_setpos(keyblob, 0);
731f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* skip the "ssh-rsa" or "ssh-dss" header */
732f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	buf_incrpos(keyblob, buf_getint(keyblob));
733f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
734f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
735f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Find the sequence of integers to be encoded into the OpenSSH
736f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * key blob, and also decide on the header line.
737f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
738f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
739f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
740f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_RSA
741f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (keytype == DROPBEAR_SIGNKEY_RSA) {
742f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
743f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
744f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
745f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
746f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
747f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
748f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* e */
749f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2].bytes = buf_getint(keyblob);
750f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
751f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[2].bytes);
752f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
753f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* n */
754f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1].bytes = buf_getint(keyblob);
755f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
756f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[1].bytes);
757f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
758f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* d */
759f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3].bytes = buf_getint(keyblob);
760f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
761f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[3].bytes);
762f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
763f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* p */
764f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4].bytes = buf_getint(keyblob);
765f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
766f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[4].bytes);
767f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
768f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* q */
769f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[5].bytes = buf_getint(keyblob);
770f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
771f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[5].bytes);
772f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
773f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* now calculate some extra parameters: */
774f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_mp_init(&tmpval);
775f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_mp_init(&dmp1);
776f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_mp_init(&dmq1);
777f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_mp_init(&iqmp);
778f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
779f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* dmp1 = d mod (p-1) */
780f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
781f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Bignum error for p-1\n");
782f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
783f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
784f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
785f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Bignum error for dmp1\n");
786f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
787f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
788f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
789f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* dmq1 = d mod (q-1) */
790f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
791f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Bignum error for q-1\n");
792f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
793f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
794f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
795f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Bignum error for dmq1\n");
796f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
797f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
798f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
799f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* iqmp = (q^-1) mod p */
800f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
801f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(stderr, "Bignum error for iqmp\n");
802f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
803f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
804f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
805f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		extrablob = buf_new(2000);
806f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_putmpint(extrablob, &dmp1);
807f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_putmpint(extrablob, &dmq1);
808f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_putmpint(extrablob, &iqmp);
809f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_setpos(extrablob, 0);
810f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		mp_clear(&dmp1);
811f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		mp_clear(&dmq1);
812f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		mp_clear(&iqmp);
813f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		mp_clear(&tmpval);
814f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
815f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* dmp1 */
816f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[6].bytes = buf_getint(extrablob);
817f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
818f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(extrablob, numbers[6].bytes);
819f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
820f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* dmq1 */
821f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[7].bytes = buf_getint(extrablob);
822f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
823f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(extrablob, numbers[7].bytes);
824f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
825f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* iqmp */
826f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[8].bytes = buf_getint(extrablob);
827f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
828f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(extrablob, numbers[8].bytes);
829f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
830f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		nnumbers = 9;
831f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		header = "-----BEGIN RSA PRIVATE KEY-----\n";
832f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		footer = "-----END RSA PRIVATE KEY-----\n";
833f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
834f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif /* DROPBEAR_RSA */
835f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
836f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#ifdef DROPBEAR_DSS
837f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (keytype == DROPBEAR_SIGNKEY_DSS) {
838f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
839f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* p */
840f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1].bytes = buf_getint(keyblob);
841f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
842f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[1].bytes);
843f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
844f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* q */
845f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2].bytes = buf_getint(keyblob);
846f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
847f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[2].bytes);
848f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
849f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* g */
850f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3].bytes = buf_getint(keyblob);
851f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
852f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[3].bytes);
853f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
854f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* y */
855f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4].bytes = buf_getint(keyblob);
856f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
857f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[4].bytes);
858f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
859f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/* x */
860f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[5].bytes = buf_getint(keyblob);
861f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
862f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_incrpos(keyblob, numbers[5].bytes);
863f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
864f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		nnumbers = 6;
865f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		header = "-----BEGIN DSA PRIVATE KEY-----\n";
866f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		footer = "-----END DSA PRIVATE KEY-----\n";
867f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
868f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif /* DROPBEAR_DSS */
869f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
870f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
871f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Now count up the total size of the ASN.1 encoded integers,
872f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * so as to determine the length of the containing SEQUENCE.
873f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
874f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	len = 0;
875f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	for (i = 0; i < nnumbers; i++) {
876f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
877f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		len += numbers[i].bytes;
878f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
879f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	seqlen = len;
880f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Now add on the SEQUENCE header. */
881f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
882f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Round up to the cipher block size, ensuring we have at least one
883f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * byte of padding (see below). */
884f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	outlen = len;
885f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (passphrase)
886f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		outlen = (outlen+8) &~ 7;
887f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
888f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
889f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Now we know how big outblob needs to be. Allocate it.
890f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
891f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	outblob = (unsigned char*)m_malloc(outlen);
892f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
893f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
894f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * And write the data into it.
895f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
896f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos = 0;
897f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
898f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	for (i = 0; i < nnumbers; i++) {
899f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
900f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
901f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += numbers[i].bytes;
902f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
903f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
904f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
905f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Padding on OpenSSH keys is deterministic. The number of
906f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * padding bytes is always more than zero, and always at most
907f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * the cipher block length. The value of each padding byte is
908f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * equal to the number of padding bytes. So a plaintext that's
909f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * an exact multiple of the block size will be padded with 08
910f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
911f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * plaintext one byte less than a multiple of the block size
912f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * will be padded with just 01.
913f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 *
914f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * This enables the OpenSSL key decryption function to strip
915f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * off the padding algorithmically and return the unpadded
916f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * plaintext to the next layer: it looks at the final byte, and
917f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * then expects to find that many bytes at the end of the data
918f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * with the same value. Those are all removed and the rest is
919f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * returned.
920f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
921f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert(pos == len);
922f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	while (pos < outlen) {
923f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		outblob[pos++] = outlen - len;
924f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
925f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
926f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
927f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Encrypt the key.
928f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
929f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (passphrase) {
930f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fprintf(stderr, "Encrypted keys aren't supported currently\n");
931f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
932f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
933f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
934f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
935f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * And save it. We'll use Unix line endings just in case it's
936f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * subsequently transferred in binary mode.
937f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
938f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (strlen(filename) == 1 && filename[0] == '-') {
939f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fp = stdout;
940f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
941f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fp = fopen(filename, "wb");	  /* ensure Unix line endings */
942f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
943f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fp) {
944f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fprintf(stderr, "Failed opening output file\n");
945f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
946f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
947f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fputs(header, fp);
948f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	base64_encode_fp(fp, outblob, outlen, 64);
949f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fputs(footer, fp);
950f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fclose(fp);
951f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = 1;
952f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
953f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
954f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (outblob) {
955f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(outblob, 0, outlen);
956f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(outblob);
957f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
958f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (keyblob) {
959f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_burn(keyblob);
960f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_free(keyblob);
961f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
962f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (extrablob) {
963f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_burn(extrablob);
964f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		buf_free(extrablob);
965f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
966f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
967f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
968f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
969f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#if 0
970f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* XXX TODO ssh.com stuff isn't going yet */
971f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
972f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/* ----------------------------------------------------------------------
973f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Code to read ssh.com private keys.
974f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
975f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
976f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project/*
977f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The format of the base64 blob is largely ssh2-packet-formatted,
978f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * except that mpints are a bit different: they're more like the
979f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * old ssh1 mpint. You have a 32-bit bit count N, followed by
980f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * (N+7)/8 bytes of data.
981f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
982f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * So. The blob contains:
983f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
984f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - uint32 0x3f6ff9eb	   (magic number)
985f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - uint32 size			 (total blob size)
986f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - string key-type		 (see below)
987f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - string cipher-type	  (tells you if key is encrypted)
988f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - string encrypted-blob
989f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
990f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * (The first size field includes the size field itself and the
991f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * magic number before it. All other size fields are ordinary ssh2
992f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * strings, so the size field indicates how much data is to
993f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * _follow_.)
994f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
995f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The encrypted blob, once decrypted, contains a single string
996f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * which in turn contains the payload. (This allows padding to be
997f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * added after that string while still making it clear where the
998f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * real payload ends. Also it probably makes for a reasonable
999f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * decryption check.)
1000f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1001f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The payload blob, for an RSA key, contains:
1002f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint e
1003f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint d
1004f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint n  (yes, the public and private stuff is intermixed)
1005f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint u  (presumably inverse of p mod q)
1006f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint p  (p is the smaller prime)
1007f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint q  (q is the larger)
1008f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1009f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * For a DSA key, the payload blob contains:
1010f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - uint32 0
1011f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint p
1012f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint g
1013f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint q
1014f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint y
1015f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - mpint x
1016f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1017f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Alternatively, if the parameters are `predefined', that
1018f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
1019f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * containing some predefined parameter specification. *shudder*,
1020f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * but I doubt we'll encounter this in real life.
1021f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1022f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * The key type strings are ghastly. The RSA key I looked at had a
1023f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * type string of
1024f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1025f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *   `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
1026f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1027f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * and the DSA key wasn't much better:
1028f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1029f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *   `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
1030f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1031f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * It isn't clear that these will always be the same. I think it
1032f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * might be wise just to look at the `if-modn{sign{rsa' and
1033f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * `dl-modp{sign{dsa' prefixes.
1034f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1035f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * Finally, the encryption. The cipher-type string appears to be
1036f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * either `none' or `3des-cbc'. Looks as if this is SSH2-style
1037f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * 3des-cbc (i.e. outer cbc rather than inner). The key is created
1038f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project * from the passphrase by means of yet another hashing faff:
1039f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *
1040f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - first 16 bytes are MD5(passphrase)
1041f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - next 16 bytes are MD5(passphrase || first 16 bytes)
1042f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *  - if there were more, they'd be MD5(passphrase || first 32),
1043f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project *	and so on.
1044f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project */
1045f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1046f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
1047f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1048f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstruct sshcom_key {
1049f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char comment[256];				 /* allowing any length is overkill */
1050f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *keyblob;
1051f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int keyblob_len, keyblob_size;
1052f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project};
1053f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1054f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic struct sshcom_key *load_sshcom_key(const char *filename)
1055f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1056f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct sshcom_key *ret;
1057f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	FILE *fp;
1058f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char buffer[256];
1059f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int len;
1060f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *errmsg, *p;
1061f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int headers_done;
1062f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char base64_bit[4];
1063f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int base64_chars = 0;
1064f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1065f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = snew(struct sshcom_key);
1066f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->comment[0] = '\0';
1067f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->keyblob = NULL;
1068f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->keyblob_len = ret->keyblob_size = 0;
1069f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1070f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fp = fopen(filename, "r");
1071f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fp) {
1072f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Unable to open key file";
1073f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1074f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1075f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fgets(buffer, sizeof(buffer), fp) ||
1076f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
1077f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "File does not begin with ssh.com key header";
1078f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1079f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1080f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1081f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	headers_done = 0;
1082f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	while (1) {
1083f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!fgets(buffer, sizeof(buffer), fp)) {
1084f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "Unexpected end of file";
1085f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
1086f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1087f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
1088f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			break;					 /* done */
1089f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if ((p = strchr(buffer, ':')) != NULL) {
1090f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (headers_done) {
1091f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				errmsg = "Header found in body of key data";
1092f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				goto error;
1093f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
1094f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			*p++ = '\0';
1095f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			while (*p && isspace((unsigned char)*p)) p++;
1096f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			/*
1097f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * Header lines can end in a trailing backslash for
1098f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 * continuation.
1099f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			 */
1100f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) ||
1101f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				   p[len-1] != '\n' || p[len-2] == '\\') {
1102f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (len > (int)((p-buffer) + sizeof(buffer)-2)) {
1103f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					errmsg = "Header line too long to deal with";
1104f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					goto error;
1105f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
1106f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
1107f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					errmsg = "Unexpected end of file";
1108f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					goto error;
1109f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
1110f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
1111f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			p[strcspn(p, "\n")] = '\0';
1112f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			if (!strcmp(buffer, "Comment")) {
1113f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				/* Strip quotes in comment if present. */
1114f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (p[0] == '"' && p[strlen(p)-1] == '"') {
1115f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					p++;
1116f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					p[strlen(p)-1] = '\0';
1117f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
1118f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				strncpy(ret->comment, p, sizeof(ret->comment));
1119f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				ret->comment[sizeof(ret->comment)-1] = '\0';
1120f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
1121f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		} else {
1122f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			headers_done = 1;
1123f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1124f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			p = buffer;
1125f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			while (isbase64(*p)) {
1126f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				base64_bit[base64_chars++] = *p;
1127f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				if (base64_chars == 4) {
1128f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					unsigned char out[3];
1129f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1130f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					base64_chars = 0;
1131f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1132f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					len = base64_decode_atom(base64_bit, out);
1133f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1134f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					if (len <= 0) {
1135f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						errmsg = "Invalid base64 encoding";
1136f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						goto error;
1137f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					}
1138f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1139f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					if (ret->keyblob_len + len > ret->keyblob_size) {
1140f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						ret->keyblob_size = ret->keyblob_len + len + 256;
1141f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project						ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
1142f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project											   unsigned char);
1143f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					}
1144f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1145f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					memcpy(ret->keyblob + ret->keyblob_len, out, len);
1146f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project					ret->keyblob_len += len;
1147f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				}
1148f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1149f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				p++;
1150f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			}
1151f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1152f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1153f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1154f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret->keyblob_len == 0 || !ret->keyblob) {
1155f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key body not present";
1156f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1157f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1158f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1159f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
1160f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1161f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
1162f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (ret) {
1163f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (ret->keyblob) {
1164f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			memset(ret->keyblob, 0, ret->keyblob_size);
1165f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			m_free(ret->keyblob);
1166f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1167f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(&ret, 0, sizeof(ret));
1168f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(ret);
1169f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1170f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return NULL;
1171f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1172f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1173f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectint sshcom_encrypted(const char *filename, char **comment)
1174f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1175f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct sshcom_key *key = load_sshcom_key(filename);
1176f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int pos, len, answer;
1177f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1178f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	*comment = NULL;
1179f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!key)
1180f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return 0;
1181f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1182f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1183f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Check magic number.
1184f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1185f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
1186f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return 0;					  /* key is invalid */
1187f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1188f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1189f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Find the cipher-type string.
1190f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1191f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	answer = 0;
1192f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos = 8;
1193f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4)
1194f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto done;					 /* key is far too short */
1195f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4 + GET_32BIT(key->keyblob + pos);   /* skip key type */
1196f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4)
1197f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto done;					 /* key is far too short */
1198f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	len = GET_32BIT(key->keyblob + pos);   /* find cipher-type length */
1199f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4+len)
1200f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto done;					 /* cipher type string is incomplete */
1201f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
1202f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		answer = 1;
1203f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1204f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	done:
1205f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	*comment = dupstr(key->comment);
1206f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(key->keyblob, 0, key->keyblob_size);
1207f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key->keyblob);
1208f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(&key, 0, sizeof(key));
1209f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key);
1210f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return answer;
1211f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1212f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1213f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
1214f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1215f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int bits;
1216f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int bytes;
1217f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *d = (unsigned char *) data;
1218f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1219f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len < 4)
1220f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1221f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	bits = GET_32BIT(d);
1222f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1223f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	bytes = (bits + 7) / 8;
1224f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len < 4+bytes)
1225f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1226f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1227f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->start = d + 4;
1228f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->bytes = bytes;
1229f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return bytes+4;
1230f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1231f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
1232f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->start = NULL;
1233f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret->bytes = -1;
1234f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return len;						/* ensure further calls fail as well */
1235f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1236f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1237f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectstatic int sshcom_put_mpint(void *target, void *data, int len)
1238f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1239f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *d = (unsigned char *)target;
1240f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *i = (unsigned char *)data;
1241f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int bits = len * 8 - 1;
1242f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1243f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	while (bits > 0) {
1244f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (*i & (1 << (bits & 7)))
1245f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			break;
1246f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!(bits-- & 7))
1247f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			i++, len--;
1248f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1249f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1250f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	PUT_32BIT(d, bits+1);
1251f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memcpy(d+4, i, len);
1252f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return len+4;
1253f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1254f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1255f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectsign_key *sshcom_read(const char *filename, char *passphrase)
1256f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1257f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct sshcom_key *key = load_sshcom_key(filename);
1258f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *errmsg;
1259f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int pos, len;
1260f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	const char prefix_rsa[] = "if-modn{sign{rsa";
1261f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	const char prefix_dsa[] = "dl-modp{sign{dsa";
1262f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	enum { RSA, DSA } type;
1263f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int encrypted;
1264f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *ciphertext;
1265f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int cipherlen;
1266f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct ssh2_userkey *ret = NULL, *retkey;
1267f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	const struct ssh_signkey *alg;
1268f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *blob = NULL;
1269f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int blobsize, publen, privlen;
1270f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1271f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!key)
1272f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		return NULL;
1273f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1274f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1275f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Check magic number.
1276f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1277f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
1278f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key does not begin with magic number";
1279f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1280f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1281f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1282f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1283f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Determine the key type.
1284f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1285f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos = 8;
1286f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4 ||
1287f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1288f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key blob does not contain a key type string";
1289f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1290f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1291f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len > sizeof(prefix_rsa) - 1 &&
1292f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		!memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
1293f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		type = RSA;
1294f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (len > sizeof(prefix_dsa) - 1 &&
1295f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		!memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
1296f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		type = DSA;
1297f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
1298f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key is of unknown type";
1299f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1300f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1301f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4+len;
1302f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1303f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1304f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Determine the cipher type.
1305f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1306f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4 ||
1307f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1308f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key blob does not contain a cipher type string";
1309f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1310f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1311f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
1312f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		encrypted = 0;
1313f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
1314f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		encrypted = 1;
1315f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	else {
1316f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key encryption is of unknown type";
1317f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1318f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1319f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4+len;
1320f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1321f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1322f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Get hold of the encrypted part of the key.
1323f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1324f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->keyblob_len < pos+4 ||
1325f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1326f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Key blob does not contain actual key data";
1327f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1328f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1329f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ciphertext = (char *)key->keyblob + pos + 4;
1330f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	cipherlen = len;
1331f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (cipherlen == 0) {
1332f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "Length of key data is zero";
1333f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1334f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1335f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1336f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1337f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Decrypt it if necessary.
1338f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1339f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (encrypted) {
1340f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
1341f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Derive encryption key from passphrase and iv/salt:
1342f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *
1343f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block A equal MD5(passphrase)
1344f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block B equal MD5(passphrase || A)
1345f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - block C would be MD5(passphrase || A || B) and so on
1346f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - encryption key is the first N bytes of A || B
1347f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
1348f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct MD5Context md5c;
1349f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		unsigned char keybuf[32], iv[8];
1350f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1351f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (cipherlen % 8 != 0) {
1352f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "Encrypted part of key is not a multiple of cipher block"
1353f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				" size";
1354f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
1355f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1356f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1357f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
1358f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1359f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf, &md5c);
1360f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1361f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
1362f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1363f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, keybuf, 16);
1364f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf+16, &md5c);
1365f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1366f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
1367f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Now decrypt the key blob.
1368f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
1369f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(iv, 0, sizeof(iv));
1370f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
1371f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project								 cipherlen);
1372f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1373f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(&md5c, 0, sizeof(md5c));
1374f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(keybuf, 0, sizeof(keybuf));
1375f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1376f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
1377f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Hereafter we return WRONG_PASSPHRASE for any parsing
1378f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * error. (But only if we've just tried to decrypt it!
1379f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Returning WRONG_PASSPHRASE for an unencrypted key is
1380f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * automatic doom.)
1381f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
1382f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (encrypted)
1383f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			ret = SSH2_WRONG_PASSPHRASE;
1384f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1385f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1386f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1387f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Strip away the containing string to get to the real meat.
1388f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1389f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	len = GET_32BIT(ciphertext);
1390f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (len > cipherlen-4) {
1391f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "containing string was ill-formed";
1392f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1393f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1394f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ciphertext += 4;
1395f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	cipherlen = len;
1396f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1397f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1398f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Now we break down into RSA versus DSA. In either case we'll
1399f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * construct public and private blobs in our own format, and
1400f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * end up feeding them to alg->createkey().
1401f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1402f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	blobsize = cipherlen + 256;
1403f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	blob = snewn(blobsize, unsigned char);
1404f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	privlen = 0;
1405f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (type == RSA) {
1406f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct mpint_pos n, e, d, u, p, q;
1407f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int pos = 0;
1408f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
1409f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
1410f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
1411f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
1412f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1413f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1414f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!q.start) {
1415f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "key data did not contain six integers";
1416f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
1417f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1418f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1419f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		alg = &ssh_rsa;
1420f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 0;
1421f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_string(blob+pos, "ssh-rsa", 7);
1422f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, e.start, e.bytes);
1423f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, n.start, n.bytes);
1424f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		publen = pos;
1425f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_string(blob+pos, d.start, d.bytes);
1426f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, q.start, q.bytes);
1427f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, p.start, p.bytes);
1428f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, u.start, u.bytes);
1429f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		privlen = pos - publen;
1430f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (type == DSA) {
1431f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct mpint_pos p, q, g, x, y;
1432f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int pos = 4;
1433f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (GET_32BIT(ciphertext) != 0) {
1434f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "predefined DSA parameters not supported";
1435f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
1436f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1437f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1438f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
1439f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1440f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
1441f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
1442f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		if (!x.start) {
1443f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			errmsg = "key data did not contain five integers";
1444f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			goto error;
1445f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1446f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1447f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		alg = &ssh_dss;
1448f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 0;
1449f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_string(blob+pos, "ssh-dss", 7);
1450f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, p.start, p.bytes);
1451f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, q.start, q.bytes);
1452f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, g.start, g.bytes);
1453f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, y.start, y.bytes);
1454f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		publen = pos;
1455f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_mp(blob+pos, x.start, x.bytes);
1456f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		privlen = pos - publen;
1457f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1458f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1459f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert(privlen > 0);			   /* should have bombed by now if not */
1460f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1461f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retkey = snew(struct ssh2_userkey);
1462f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retkey->alg = alg;
1463f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
1464f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!retkey->data) {
1465f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(retkey);
1466f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		errmsg = "unable to create key data structure";
1467f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1468f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1469f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	retkey->comment = dupstr(key->comment);
1470f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1471f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	errmsg = NULL; /* no error */
1472f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = retkey;
1473f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1474f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
1475f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (blob) {
1476f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(blob, 0, blobsize);
1477f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(blob);
1478f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1479f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(key->keyblob, 0, key->keyblob_size);
1480f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key->keyblob);
1481f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	memset(&key, 0, sizeof(key));
1482f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	m_free(key);
1483f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
1484f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1485f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1486f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Projectint sshcom_write(const char *filename, sign_key *key,
1487f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project				 char *passphrase)
1488f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project{
1489f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *pubblob, *privblob;
1490f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int publen, privlen;
1491f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	unsigned char *outblob;
1492f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int outlen;
1493f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	struct mpint_pos numbers[6];
1494f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int nnumbers, initial_zero, pos, lenpos, i;
1495f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *type;
1496f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	char *ciphertext;
1497f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int cipherlen;
1498f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	int ret = 0;
1499f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	FILE *fp;
1500f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1501f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1502f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Fetch the key blobs.
1503f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1504f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pubblob = key->alg->public_blob(key->data, &publen);
1505f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	privblob = key->alg->private_blob(key->data, &privlen);
1506f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	outblob = NULL;
1507f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1508f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1509f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Find the sequence of integers to be encoded into the OpenSSH
1510f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * key blob, and also decide on the header line.
1511f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1512f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (key->alg == &ssh_rsa) {
1513f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int pos;
1514f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct mpint_pos n, e, d, p, q, iqmp;
1515f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1516f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 4 + GET_32BIT(pubblob);
1517f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
1518f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
1519f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 0;
1520f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
1521f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
1522f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
1523f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
1524f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1525f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		dropbear_assert(e.start && iqmp.start); /* can't go wrong */
1526f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1527f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[0] = e;
1528f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1] = d;
1529f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2] = n;
1530f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3] = iqmp;
1531f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4] = q;
1532f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[5] = p;
1533f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1534f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		nnumbers = 6;
1535f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		initial_zero = 0;
1536f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
1537f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else if (key->alg == &ssh_dss) {
1538f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int pos;
1539f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct mpint_pos p, q, g, y, x;
1540f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1541f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 4 + GET_32BIT(pubblob);
1542f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
1543f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
1544f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
1545f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
1546f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos = 0;
1547f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
1548f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1549f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		dropbear_assert(y.start && x.start); /* can't go wrong */
1550f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1551f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[0] = p;
1552f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[1] = g;
1553f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[2] = q;
1554f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[3] = y;
1555f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		numbers[4] = x;
1556f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1557f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		nnumbers = 5;
1558f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		initial_zero = 1;
1559f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
1560f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	} else {
1561f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		dropbear_assert(0);					 /* zoinks! */
1562f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1563f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1564f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1565f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Total size of key blob will be somewhere under 512 plus
1566f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * combined length of integers. We'll calculate the more
1567f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * precise size as we construct the blob.
1568f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1569f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	outlen = 512;
1570f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	for (i = 0; i < nnumbers; i++)
1571f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		outlen += 4 + numbers[i].bytes;
1572f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	outblob = snewn(outlen, unsigned char);
1573f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1574f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1575f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Create the unencrypted key blob.
1576f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1577f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos = 0;
1578f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
1579f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4;							   /* length field, fill in later */
1580f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += put_string(outblob+pos, type, strlen(type));
1581f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	{
1582f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		char *ciphertype = passphrase ? "3des-cbc" : "none";
1583f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
1584f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1585f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	lenpos = pos;					   /* remember this position */
1586f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4;							   /* encrypted-blob size */
1587f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	pos += 4;							   /* encrypted-payload size */
1588f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (initial_zero) {
1589f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		PUT_32BIT(outblob+pos, 0);
1590f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += 4;
1591f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1592f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	for (i = 0; i < nnumbers; i++)
1593f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		pos += sshcom_put_mpint(outblob+pos,
1594f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project								numbers[i].start, numbers[i].bytes);
1595f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Now wrap up the encrypted payload. */
1596f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
1597f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Pad encrypted blob to a multiple of cipher block size. */
1598f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (passphrase) {
1599f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int padding = -(pos - (lenpos+4)) & 7;
1600f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while (padding--)
1601f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			outblob[pos++] = random_byte();
1602f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1603f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ciphertext = (char *)outblob+lenpos+4;
1604f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	cipherlen = pos - (lenpos+4);
1605f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert(!passphrase || cipherlen % 8 == 0);
1606f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* Wrap up the encrypted blob string. */
1607f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	PUT_32BIT(outblob+lenpos, cipherlen);
1608f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/* And finally fill in the total length field. */
1609f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	PUT_32BIT(outblob+4, pos);
1610f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1611f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	dropbear_assert(pos < outlen);
1612f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1613f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1614f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Encrypt the key.
1615f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1616f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (passphrase) {
1617f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
1618f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Derive encryption key from passphrase and iv/salt:
1619f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *
1620f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block A equal MD5(passphrase)
1621f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - let block B equal MD5(passphrase || A)
1622f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - block C would be MD5(passphrase || A || B) and so on
1623f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 *  - encryption key is the first N bytes of A || B
1624f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
1625f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		struct MD5Context md5c;
1626f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		unsigned char keybuf[32], iv[8];
1627f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1628f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
1629f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1630f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf, &md5c);
1631f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1632f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Init(&md5c);
1633f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1634f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Update(&md5c, keybuf, 16);
1635f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		MD5Final(keybuf+16, &md5c);
1636f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1637f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		/*
1638f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 * Now decrypt the key blob.
1639f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		 */
1640f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(iv, 0, sizeof(iv));
1641f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
1642f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project								 cipherlen);
1643f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1644f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(&md5c, 0, sizeof(md5c));
1645f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(keybuf, 0, sizeof(keybuf));
1646f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1647f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1648f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1649f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * And save it. We'll use Unix line endings just in case it's
1650f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * subsequently transferred in binary mode.
1651f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1652f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fp = fopen(filename, "wb");	  /* ensure Unix line endings */
1653f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (!fp)
1654f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		goto error;
1655f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1656f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fprintf(fp, "Comment: \"");
1657f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	/*
1658f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Comment header is broken with backslash-newline if it goes
1659f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * over 70 chars. Although it's surrounded by quotes, it
1660f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * _doesn't_ escape backslashes or quotes within the string.
1661f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 * Don't ask me, I didn't design it.
1662f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	 */
1663f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	{
1664f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		int slen = 60;					   /* starts at 60 due to "Comment: " */
1665f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		char *c = key->comment;
1666f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		while ((int)strlen(c) > slen) {
1667f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			fprintf(fp, "%.*s\\\n", slen, c);
1668f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			c += slen;
1669f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project			slen = 70;					   /* allow 70 chars on subsequent lines */
1670f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		}
1671f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		fprintf(fp, "%s\"\n", c);
1672f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1673f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	base64_encode_fp(fp, outblob, pos, 70);
1674f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1675f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	fclose(fp);
1676f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	ret = 1;
1677f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project
1678f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	error:
1679f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (outblob) {
1680f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(outblob, 0, outlen);
1681f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(outblob);
1682f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1683f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (privblob) {
1684f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(privblob, 0, privlen);
1685f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(privblob);
1686f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1687f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	if (pubblob) {
1688f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		memset(pubblob, 0, publen);
1689f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project		m_free(pubblob);
1690f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	}
1691f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project	return ret;
1692f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project}
1693f7fc46c63fdc8f39234fea409b8dbe116d73ebf8The Android Open Source Project#endif /* ssh.com stuff disabled */
1694