comparison keyimport.c @ 1914:f978a15194ba

Remove commented ssh.com code from keyimport
author Matt Johnston <matt@ucc.asn.au>
date Wed, 30 Mar 2022 10:10:15 +0800
parents 38c6fd7d7a82
children
comparison
equal deleted inserted replaced
1913:38c6fd7d7a82 1914:f978a15194ba
1 /* 1 /*
2 * Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com 2 * Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
3 * keyfiles. 3 * keyfiles.
4 * 4 *
5 * Modifications copyright 2003 Matt Johnston 5 * Modifications copyright 2003-2022 Matt Johnston
6 * 6 *
7 * PuTTY is copyright 1997-2003 Simon Tatham. 7 * PuTTY is copyright 1997-2003 Simon Tatham.
8 * 8 *
9 * Portions copyright Robert de Bath, Joris van Rantwijk, Delian 9 * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
10 * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, 10 * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
1119 buf_burn_free(extrablob); 1119 buf_burn_free(extrablob);
1120 } 1120 }
1121 return ret; 1121 return ret;
1122 } 1122 }
1123 1123
1124 #if 0
1125 /* XXX TODO ssh.com stuff isn't going yet */
1126
1127 /* ----------------------------------------------------------------------
1128 * Code to read ssh.com private keys.
1129 */
1130
1131 /*
1132 * The format of the base64 blob is largely ssh2-packet-formatted,
1133 * except that mpints are a bit different: they're more like the
1134 * old ssh1 mpint. You have a 32-bit bit count N, followed by
1135 * (N+7)/8 bytes of data.
1136 *
1137 * So. The blob contains:
1138 *
1139 * - uint32 0x3f6ff9eb (magic number)
1140 * - uint32 size (total blob size)
1141 * - string key-type (see below)
1142 * - string cipher-type (tells you if key is encrypted)
1143 * - string encrypted-blob
1144 *
1145 * (The first size field includes the size field itself and the
1146 * magic number before it. All other size fields are ordinary ssh2
1147 * strings, so the size field indicates how much data is to
1148 * _follow_.)
1149 *
1150 * The encrypted blob, once decrypted, contains a single string
1151 * which in turn contains the payload. (This allows padding to be
1152 * added after that string while still making it clear where the
1153 * real payload ends. Also it probably makes for a reasonable
1154 * decryption check.)
1155 *
1156 * The payload blob, for an RSA key, contains:
1157 * - mpint e
1158 * - mpint d
1159 * - mpint n (yes, the public and private stuff is intermixed)
1160 * - mpint u (presumably inverse of p mod q)
1161 * - mpint p (p is the smaller prime)
1162 * - mpint q (q is the larger)
1163 *
1164 * For a DSA key, the payload blob contains:
1165 * - uint32 0
1166 * - mpint p
1167 * - mpint g
1168 * - mpint q
1169 * - mpint y
1170 * - mpint x
1171 *
1172 * Alternatively, if the parameters are `predefined', that
1173 * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
1174 * containing some predefined parameter specification. *shudder*,
1175 * but I doubt we'll encounter this in real life.
1176 *
1177 * The key type strings are ghastly. The RSA key I looked at had a
1178 * type string of
1179 *
1180 * `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
1181 *
1182 * and the DSA key wasn't much better:
1183 *
1184 * `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
1185 *
1186 * It isn't clear that these will always be the same. I think it
1187 * might be wise just to look at the `if-modn{sign{rsa' and
1188 * `dl-modp{sign{dsa' prefixes.
1189 *
1190 * Finally, the encryption. The cipher-type string appears to be
1191 * either `none' or `3des-cbc'. Looks as if this is SSH2-style
1192 * 3des-cbc (i.e. outer cbc rather than inner). The key is created
1193 * from the passphrase by means of yet another hashing faff:
1194 *
1195 * - first 16 bytes are MD5(passphrase)
1196 * - next 16 bytes are MD5(passphrase || first 16 bytes)
1197 * - if there were more, they'd be MD5(passphrase || first 32),
1198 * and so on.
1199 */
1200
1201 #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
1202
1203 struct sshcom_key {
1204 char comment[256]; /* allowing any length is overkill */
1205 unsigned char *keyblob;
1206 int keyblob_len, keyblob_size;
1207 };
1208
1209 static struct sshcom_key *load_sshcom_key(const char *filename)
1210 {
1211 struct sshcom_key *ret;
1212 FILE *fp;
1213 char buffer[256];
1214 int len;
1215 char *errmsg, *p;
1216 int headers_done;
1217 char base64_bit[4];
1218 int base64_chars = 0;
1219
1220 ret = snew(struct sshcom_key);
1221 ret->comment[0] = '\0';
1222 ret->keyblob = NULL;
1223 ret->keyblob_len = ret->keyblob_size = 0;
1224
1225 fp = fopen(filename, "r");
1226 if (!fp) {
1227 errmsg = "Unable to open key file";
1228 goto error;
1229 }
1230 if (!fgets(buffer, sizeof(buffer), fp) ||
1231 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
1232 errmsg = "File does not begin with ssh.com key header";
1233 goto error;
1234 }
1235
1236 headers_done = 0;
1237 while (1) {
1238 if (!fgets(buffer, sizeof(buffer), fp)) {
1239 errmsg = "Unexpected end of file";
1240 goto error;
1241 }
1242 if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
1243 break; /* done */
1244 if ((p = strchr(buffer, ':')) != NULL) {
1245 if (headers_done) {
1246 errmsg = "Header found in body of key data";
1247 goto error;
1248 }
1249 *p++ = '\0';
1250 while (*p && isspace((unsigned char)*p)) p++;
1251 /*
1252 * Header lines can end in a trailing backslash for
1253 * continuation.
1254 */
1255 while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) ||
1256 p[len-1] != '\n' || p[len-2] == '\\') {
1257 if (len > (int)((p-buffer) + sizeof(buffer)-2)) {
1258 errmsg = "Header line too long to deal with";
1259 goto error;
1260 }
1261 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
1262 errmsg = "Unexpected end of file";
1263 goto error;
1264 }
1265 }
1266 p[strcspn(p, "\n")] = '\0';
1267 if (!strcmp(buffer, "Comment")) {
1268 /* Strip quotes in comment if present. */
1269 if (p[0] == '"' && p[strlen(p)-1] == '"') {
1270 p++;
1271 p[strlen(p)-1] = '\0';
1272 }
1273 strncpy(ret->comment, p, sizeof(ret->comment));
1274 ret->comment[sizeof(ret->comment)-1] = '\0';
1275 }
1276 } else {
1277 headers_done = 1;
1278
1279 p = buffer;
1280 while (isbase64(*p)) {
1281 base64_bit[base64_chars++] = *p;
1282 if (base64_chars == 4) {
1283 unsigned char out[3];
1284
1285 base64_chars = 0;
1286
1287 len = base64_decode_atom(base64_bit, out);
1288
1289 if (len <= 0) {
1290 errmsg = "Invalid base64 encoding";
1291 goto error;
1292 }
1293
1294 if (ret->keyblob_len + len > ret->keyblob_size) {
1295 ret->keyblob_size = ret->keyblob_len + len + 256;
1296 ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
1297 unsigned char);
1298 }
1299
1300 memcpy(ret->keyblob + ret->keyblob_len, out, len);
1301 ret->keyblob_len += len;
1302 }
1303
1304 p++;
1305 }
1306 }
1307 }
1308
1309 if (ret->keyblob_len == 0 || !ret->keyblob) {
1310 errmsg = "Key body not present";
1311 goto error;
1312 }
1313
1314 return ret;
1315
1316 error:
1317 if (ret) {
1318 if (ret->keyblob) {
1319 memset(ret->keyblob, 0, ret->keyblob_size);
1320 m_free(ret->keyblob);
1321 }
1322 memset(ret, 0, sizeof(*ret));
1323 m_free(ret);
1324 }
1325 return NULL;
1326 }
1327
1328 int sshcom_encrypted(const char *filename, char **comment)
1329 {
1330 struct sshcom_key *key = load_sshcom_key(filename);
1331 int pos, len, answer;
1332
1333 *comment = NULL;
1334 if (!key)
1335 return 0;
1336
1337 /*
1338 * Check magic number.
1339 */
1340 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
1341 return 0; /* key is invalid */
1342
1343 /*
1344 * Find the cipher-type string.
1345 */
1346 answer = 0;
1347 pos = 8;
1348 if (key->keyblob_len < pos+4)
1349 goto done; /* key is far too short */
1350 len = toint(GET_32BIT(key->keyblob + pos));
1351 if (len < 0 || len > key->keyblob_len - pos - 4)
1352 goto done; /* key is far too short */
1353 pos += 4 + len; /* skip key type */
1354 len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */
1355 if (len < 0 || len > key->keyblob_len - pos - 4)
1356 goto done; /* cipher type string is incomplete */
1357 if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
1358 answer = 1;
1359
1360 done:
1361 *comment = dupstr(key->comment);
1362 memset(key->keyblob, 0, key->keyblob_size);
1363 m_free(key->keyblob);
1364 memset(key, 0, sizeof(*key));
1365 m_free(key);
1366 return answer;
1367 }
1368
1369 static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
1370 {
1371 unsigned bits, bytes;
1372 unsigned char *d = (unsigned char *) data;
1373
1374 if (len < 4)
1375 goto error;
1376 bits = GET_32BIT(d);
1377
1378 bytes = (bits + 7) / 8;
1379 if (len < 4+bytes)
1380 goto error;
1381
1382 ret->start = d + 4;
1383 ret->bytes = bytes;
1384 return bytes+4;
1385
1386 error:
1387 ret->start = NULL;
1388 ret->bytes = -1;
1389 return len; /* ensure further calls fail as well */
1390 }
1391
1392 static int sshcom_put_mpint(void *target, void *data, int len)
1393 {
1394 unsigned char *d = (unsigned char *)target;
1395 unsigned char *i = (unsigned char *)data;
1396 int bits = len * 8 - 1;
1397
1398 while (bits > 0) {
1399 if (*i & (1 << (bits & 7)))
1400 break;
1401 if (!(bits-- & 7))
1402 i++, len--;
1403 }
1404
1405 PUT_32BIT(d, bits+1);
1406 memcpy(d+4, i, len);
1407 return len+4;
1408 }
1409
1410 sign_key *sshcom_read(const char *filename, char *passphrase)
1411 {
1412 struct sshcom_key *key = load_sshcom_key(filename);
1413 char *errmsg;
1414 int pos, len;
1415 const char prefix_rsa[] = "if-modn{sign{rsa";
1416 const char prefix_dsa[] = "dl-modp{sign{dsa";
1417 enum { RSA, DSA } type;
1418 int encrypted;
1419 char *ciphertext;
1420 int cipherlen;
1421 struct ssh2_userkey *ret = NULL, *retkey;
1422 const struct ssh_signkey *alg;
1423 unsigned char *blob = NULL;
1424 int blobsize = 0, publen, privlen;
1425
1426 if (!key)
1427 return NULL;
1428
1429 /*
1430 * Check magic number.
1431 */
1432 if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
1433 errmsg = "Key does not begin with magic number";
1434 goto error;
1435 }
1436
1437 /*
1438 * Determine the key type.
1439 */
1440 pos = 8;
1441 if (key->keyblob_len < pos+4 ||
1442 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1443 errmsg = "Key blob does not contain a key type string";
1444 goto error;
1445 }
1446 if (len > sizeof(prefix_rsa) - 1 &&
1447 !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
1448 type = RSA;
1449 } else if (len > sizeof(prefix_dsa) - 1 &&
1450 !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
1451 type = DSA;
1452 } else {
1453 errmsg = "Key is of unknown type";
1454 goto error;
1455 }
1456 pos += 4+len;
1457
1458 /*
1459 * Determine the cipher type.
1460 */
1461 if (key->keyblob_len < pos+4 ||
1462 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1463 errmsg = "Key blob does not contain a cipher type string";
1464 goto error;
1465 }
1466 if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
1467 encrypted = 0;
1468 else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
1469 encrypted = 1;
1470 else {
1471 errmsg = "Key encryption is of unknown type";
1472 goto error;
1473 }
1474 pos += 4+len;
1475
1476 /*
1477 * Get hold of the encrypted part of the key.
1478 */
1479 if (key->keyblob_len < pos+4 ||
1480 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1481 errmsg = "Key blob does not contain actual key data";
1482 goto error;
1483 }
1484 ciphertext = (char *)key->keyblob + pos + 4;
1485 cipherlen = len;
1486 if (cipherlen == 0) {
1487 errmsg = "Length of key data is zero";
1488 goto error;
1489 }
1490
1491 /*
1492 * Decrypt it if necessary.
1493 */
1494 if (encrypted) {
1495 /*
1496 * Derive encryption key from passphrase and iv/salt:
1497 *
1498 * - let block A equal MD5(passphrase)
1499 * - let block B equal MD5(passphrase || A)
1500 * - block C would be MD5(passphrase || A || B) and so on
1501 * - encryption key is the first N bytes of A || B
1502 */
1503 struct MD5Context md5c;
1504 unsigned char keybuf[32], iv[8];
1505
1506 if (cipherlen % 8 != 0) {
1507 errmsg = "Encrypted part of key is not a multiple of cipher block"
1508 " size";
1509 goto error;
1510 }
1511
1512 MD5Init(&md5c);
1513 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1514 MD5Final(keybuf, &md5c);
1515
1516 MD5Init(&md5c);
1517 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1518 MD5Update(&md5c, keybuf, 16);
1519 MD5Final(keybuf+16, &md5c);
1520
1521 /*
1522 * Now decrypt the key blob.
1523 */
1524 memset(iv, 0, sizeof(iv));
1525 des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
1526 cipherlen);
1527
1528 memset(&md5c, 0, sizeof(md5c));
1529 memset(keybuf, 0, sizeof(keybuf));
1530
1531 /*
1532 * Hereafter we return WRONG_PASSPHRASE for any parsing
1533 * error. (But only if we've just tried to decrypt it!
1534 * Returning WRONG_PASSPHRASE for an unencrypted key is
1535 * automatic doom.)
1536 */
1537 if (encrypted)
1538 ret = SSH2_WRONG_PASSPHRASE;
1539 }
1540
1541 /*
1542 * Strip away the containing string to get to the real meat.
1543 */
1544 len = toint(GET_32BIT(ciphertext));
1545 if (len < 0 || len > cipherlen-4) {
1546 errmsg = "containing string was ill-formed";
1547 goto error;
1548 }
1549 ciphertext += 4;
1550 cipherlen = len;
1551
1552 /*
1553 * Now we break down into RSA versus DSA. In either case we'll
1554 * construct public and private blobs in our own format, and
1555 * end up feeding them to alg->createkey().
1556 */
1557 blobsize = cipherlen + 256;
1558 blob = snewn(blobsize, unsigned char);
1559 privlen = 0;
1560 if (type == RSA) {
1561 struct mpint_pos n, e, d, u, p, q;
1562 int pos = 0;
1563 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
1564 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
1565 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
1566 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
1567 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1568 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1569 if (!q.start) {
1570 errmsg = "key data did not contain six integers";
1571 goto error;
1572 }
1573
1574 alg = &ssh_rsa;
1575 pos = 0;
1576 pos += put_string(blob+pos, "ssh-rsa", 7);
1577 pos += put_mp(blob+pos, e.start, e.bytes);
1578 pos += put_mp(blob+pos, n.start, n.bytes);
1579 publen = pos;
1580 pos += put_string(blob+pos, d.start, d.bytes);
1581 pos += put_mp(blob+pos, q.start, q.bytes);
1582 pos += put_mp(blob+pos, p.start, p.bytes);
1583 pos += put_mp(blob+pos, u.start, u.bytes);
1584 privlen = pos - publen;
1585 } else if (type == DSA) {
1586 struct mpint_pos p, q, g, x, y;
1587 int pos = 4;
1588 if (GET_32BIT(ciphertext) != 0) {
1589 errmsg = "predefined DSA parameters not supported";
1590 goto error;
1591 }
1592 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1593 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
1594 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1595 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
1596 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
1597 if (!x.start) {
1598 errmsg = "key data did not contain five integers";
1599 goto error;
1600 }
1601
1602 alg = &ssh_dss;
1603 pos = 0;
1604 pos += put_string(blob+pos, "ssh-dss", 7);
1605 pos += put_mp(blob+pos, p.start, p.bytes);
1606 pos += put_mp(blob+pos, q.start, q.bytes);
1607 pos += put_mp(blob+pos, g.start, g.bytes);
1608 pos += put_mp(blob+pos, y.start, y.bytes);
1609 publen = pos;
1610 pos += put_mp(blob+pos, x.start, x.bytes);
1611 privlen = pos - publen;
1612 } else
1613 return NULL;
1614
1615 dropbear_assert(privlen > 0); /* should have bombed by now if not */
1616
1617 retkey = snew(struct ssh2_userkey);
1618 retkey->alg = alg;
1619 retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
1620 if (!retkey->data) {
1621 m_free(retkey);
1622 errmsg = "unable to create key data structure";
1623 goto error;
1624 }
1625 retkey->comment = dupstr(key->comment);
1626
1627 errmsg = NULL; /* no error */
1628 ret = retkey;
1629
1630 error:
1631 if (blob) {
1632 memset(blob, 0, blobsize);
1633 m_free(blob);
1634 }
1635 memset(key->keyblob, 0, key->keyblob_size);
1636 m_free(key->keyblob);
1637 memset(key, 0, sizeof(*key));
1638 m_free(key);
1639 return ret;
1640 }
1641
1642 int sshcom_write(const char *filename, sign_key *key,
1643 char *passphrase)
1644 {
1645 unsigned char *pubblob, *privblob;
1646 int publen, privlen;
1647 unsigned char *outblob;
1648 int outlen;
1649 struct mpint_pos numbers[6];
1650 int nnumbers, initial_zero, pos, lenpos, i;
1651 char *type;
1652 char *ciphertext;
1653 int cipherlen;
1654 int ret = 0;
1655 FILE *fp;
1656
1657 /*
1658 * Fetch the key blobs.
1659 */
1660 pubblob = key->alg->public_blob(key->data, &publen);
1661 privblob = key->alg->private_blob(key->data, &privlen);
1662 outblob = NULL;
1663
1664 /*
1665 * Find the sequence of integers to be encoded into the OpenSSH
1666 * key blob, and also decide on the header line.
1667 */
1668 if (key->alg == &ssh_rsa) {
1669 int pos;
1670 struct mpint_pos n, e, d, p, q, iqmp;
1671
1672 pos = 4 + GET_32BIT(pubblob);
1673 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
1674 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
1675 pos = 0;
1676 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
1677 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
1678 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
1679 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
1680
1681 dropbear_assert(e.start && iqmp.start); /* can't go wrong */
1682
1683 numbers[0] = e;
1684 numbers[1] = d;
1685 numbers[2] = n;
1686 numbers[3] = iqmp;
1687 numbers[4] = q;
1688 numbers[5] = p;
1689
1690 nnumbers = 6;
1691 initial_zero = 0;
1692 type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
1693 } else if (key->alg == &ssh_dss) {
1694 int pos;
1695 struct mpint_pos p, q, g, y, x;
1696
1697 pos = 4 + GET_32BIT(pubblob);
1698 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
1699 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
1700 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
1701 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
1702 pos = 0;
1703 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
1704
1705 dropbear_assert(y.start && x.start); /* can't go wrong */
1706
1707 numbers[0] = p;
1708 numbers[1] = g;
1709 numbers[2] = q;
1710 numbers[3] = y;
1711 numbers[4] = x;
1712
1713 nnumbers = 5;
1714 initial_zero = 1;
1715 type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
1716 } else {
1717 dropbear_assert(0); /* zoinks! */
1718 }
1719
1720 /*
1721 * Total size of key blob will be somewhere under 512 plus
1722 * combined length of integers. We'll calculate the more
1723 * precise size as we construct the blob.
1724 */
1725 outlen = 512;
1726 for (i = 0; i < nnumbers; i++)
1727 outlen += 4 + numbers[i].bytes;
1728 outblob = snewn(outlen, unsigned char);
1729
1730 /*
1731 * Create the unencrypted key blob.
1732 */
1733 pos = 0;
1734 PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
1735 pos += 4; /* length field, fill in later */
1736 pos += put_string(outblob+pos, type, strlen(type));
1737 {
1738 char *ciphertype = passphrase ? "3des-cbc" : "none";
1739 pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
1740 }
1741 lenpos = pos; /* remember this position */
1742 pos += 4; /* encrypted-blob size */
1743 pos += 4; /* encrypted-payload size */
1744 if (initial_zero) {
1745 PUT_32BIT(outblob+pos, 0);
1746 pos += 4;
1747 }
1748 for (i = 0; i < nnumbers; i++)
1749 pos += sshcom_put_mpint(outblob+pos,
1750 numbers[i].start, numbers[i].bytes);
1751 /* Now wrap up the encrypted payload. */
1752 PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
1753 /* Pad encrypted blob to a multiple of cipher block size. */
1754 if (passphrase) {
1755 int padding = -(pos - (lenpos+4)) & 7;
1756 while (padding--)
1757 outblob[pos++] = random_byte();
1758 }
1759 ciphertext = (char *)outblob+lenpos+4;
1760 cipherlen = pos - (lenpos+4);
1761 dropbear_assert(!passphrase || cipherlen % 8 == 0);
1762 /* Wrap up the encrypted blob string. */
1763 PUT_32BIT(outblob+lenpos, cipherlen);
1764 /* And finally fill in the total length field. */
1765 PUT_32BIT(outblob+4, pos);
1766
1767 dropbear_assert(pos < outlen);
1768
1769 /*
1770 * Encrypt the key.
1771 */
1772 if (passphrase) {
1773 /*
1774 * Derive encryption key from passphrase and iv/salt:
1775 *
1776 * - let block A equal MD5(passphrase)
1777 * - let block B equal MD5(passphrase || A)
1778 * - block C would be MD5(passphrase || A || B) and so on
1779 * - encryption key is the first N bytes of A || B
1780 */
1781 struct MD5Context md5c;
1782 unsigned char keybuf[32], iv[8];
1783
1784 MD5Init(&md5c);
1785 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1786 MD5Final(keybuf, &md5c);
1787
1788 MD5Init(&md5c);
1789 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
1790 MD5Update(&md5c, keybuf, 16);
1791 MD5Final(keybuf+16, &md5c);
1792
1793 /*
1794 * Now decrypt the key blob.
1795 */
1796 memset(iv, 0, sizeof(iv));
1797 des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
1798 cipherlen);
1799
1800 memset(&md5c, 0, sizeof(md5c));
1801 memset(keybuf, 0, sizeof(keybuf));
1802 }
1803
1804 /*
1805 * And save it. We'll use Unix line endings just in case it's
1806 * subsequently transferred in binary mode.
1807 */
1808 fp = fopen(filename, "wb"); /* ensure Unix line endings */
1809 if (!fp)
1810 goto error;
1811 fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1812 fprintf(fp, "Comment: \"");
1813 /*
1814 * Comment header is broken with backslash-newline if it goes
1815 * over 70 chars. Although it's surrounded by quotes, it
1816 * _doesn't_ escape backslashes or quotes within the string.
1817 * Don't ask me, I didn't design it.
1818 */
1819 {
1820 int slen = 60; /* starts at 60 due to "Comment: " */
1821 char *c = key->comment;
1822 while ((int)strlen(c) > slen) {
1823 fprintf(fp, "%.*s\\\n", slen, c);
1824 c += slen;
1825 slen = 70; /* allow 70 chars on subsequent lines */
1826 }
1827 fprintf(fp, "%s\"\n", c);
1828 }
1829 base64_encode_fp(fp, outblob, pos, 70);
1830 fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1831 fclose(fp);
1832 ret = 1;
1833
1834 error:
1835 if (outblob) {
1836 memset(outblob, 0, outlen);
1837 m_free(outblob);
1838 }
1839 if (privblob) {
1840 memset(privblob, 0, privlen);
1841 m_free(privblob);
1842 }
1843 if (pubblob) {
1844 memset(pubblob, 0, publen);
1845 m_free(pubblob);
1846 }
1847 return ret;
1848 }
1849 #endif /* ssh.com stuff disabled */
1850
1851 /* From PuTTY misc.c */ 1124 /* From PuTTY misc.c */
1852 static int toint(unsigned u) 1125 static int toint(unsigned u)
1853 { 1126 {
1854 /* 1127 /*
1855 * Convert an unsigned to an int, without running into the 1128 * Convert an unsigned to an int, without running into the