From 1da5a874f62ecc4a7593606020a230ba6a885aa3 Mon Sep 17 00:00:00 2001 From: Eugeny Date: Thu, 6 Jan 2022 21:37:25 +0100 Subject: [PATCH] node-sshpk#27 PuTTY private key support (#76) Reviewed by: Alex Wilson Reviewed by: Brian Bennett --- lib/formats/putty.js | 102 ++++++++++++++++++++++++++++++++++++++-- lib/private-key.js | 1 + test/assets/dsa-ppk | 20 ++++++++ test/assets/dsa-ppk.pub | 1 - test/assets/dsa-pub.ppk | 38 +++++++-------- test/assets/dsa.ppk | 42 ++++++++--------- test/assets/ecdsa-ppk | 5 ++ test/assets/ecdsa.ppk | 10 ++++ test/assets/ed25519-ppk | 4 ++ test/assets/ed25519.ppk | 9 ++++ test/assets/ppk3 | 26 ++++++++++ test/assets/ppk3.pem | 22 +++++++++ test/assets/rsa-ppk | 22 +++++++++ test/assets/rsa.ppk | 44 ++++++++--------- test/putty.js | 72 +++++++++++++++++++++++----- 15 files changed, 338 insertions(+), 80 deletions(-) create mode 100644 test/assets/dsa-ppk delete mode 100644 test/assets/dsa-ppk.pub create mode 100644 test/assets/ecdsa-ppk create mode 100644 test/assets/ecdsa.ppk create mode 100644 test/assets/ed25519-ppk create mode 100644 test/assets/ed25519.ppk create mode 100644 test/assets/ppk3 create mode 100644 test/assets/ppk3.pem create mode 100644 test/assets/rsa-ppk diff --git a/lib/formats/putty.js b/lib/formats/putty.js index 344419f..ab62948 100644 --- a/lib/formats/putty.js +++ b/lib/formats/putty.js @@ -9,20 +9,30 @@ var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var rfc4253 = require('./rfc4253'); var Key = require('../key'); +var SSHBuffer = require('../ssh-buffer'); +var crypto = require('crypto'); +var PrivateKey = require('../private-key'); var errors = require('../errors'); +// https://tartarus.org/~simon/putty-prerel-snapshots/htmldoc/AppendixC.html function read(buf, options) { var lines = buf.toString('ascii').split(/[\r\n]+/); var found = false; var parts; var si = 0; + var formatVersion; while (si < lines.length) { parts = splitHeader(lines[si++]); - if (parts && - parts[0].toLowerCase() === 'putty-user-key-file-2') { - found = true; - break; + if (parts) { + formatVersion = { + 'putty-user-key-file-2': 2, + 'putty-user-key-file-3': 3, + }[parts[0].toLowerCase()] + if (formatVersion) { + found = true; + break; + } } } if (!found) { @@ -32,6 +42,7 @@ function read(buf, options) { parts = splitHeader(lines[si++]); assert.equal(parts[0].toLowerCase(), 'encryption'); + var encryption = parts[1]; parts = splitHeader(lines[si++]); assert.equal(parts[0].toLowerCase(), 'comment'); @@ -52,10 +63,93 @@ function read(buf, options) { if (key.type !== keyType) { throw (new Error('Outer key algorithm mismatch')); } + + si += publicLines; + if (lines[si]) { + parts = splitHeader(lines[si++]); + assert.equal(parts[0].toLowerCase(), 'private-lines'); + var privateLines = parseInt(parts[1], 10); + if (!isFinite(privateLines) || privateLines < 0 || + privateLines > lines.length) { + throw (new Error('Invalid private-lines count')); + } + + var privateBuf = Buffer.from( + lines.slice(si, si + privateLines).join(''), 'base64'); + + if (encryption !== 'none' && formatVersion === 3) { + throw new Error('Encrypted keys arenot supported for PuTTY format version 3'); + } + + if (encryption === 'aes256-cbc') { + if (!options.passphrase) { + throw (new errors.KeyEncryptedError( + options.filename, 'PEM')); + } + + var iv = Buffer.alloc(16, 0); + var decipher = crypto.createDecipheriv( + 'aes-256-cbc', + derivePPK2EncryptionKey(options.passphrase), + iv); + decipher.setAutoPadding(false); + privateBuf = Buffer.concat([ + decipher.update(privateBuf), decipher.final()]); + } + + key = new PrivateKey(key); + if (key.type !== keyType) { + throw (new Error('Outer key algorithm mismatch')); + } + + var sshbuf = new SSHBuffer({buffer: privateBuf}); + var privateKeyParts; + if (alg === 'ssh-dss') { + privateKeyParts = [ { + name: 'x', + data: sshbuf.readBuffer() + }]; + } else if (alg === 'ssh-rsa') { + privateKeyParts = [ + { name: 'd', data: sshbuf.readBuffer() }, + { name: 'p', data: sshbuf.readBuffer() }, + { name: 'q', data: sshbuf.readBuffer() }, + { name: 'iqmp', data: sshbuf.readBuffer() } + ]; + } else if (alg.startsWith('ecdsa-sha2-nistp')) { + privateKeyParts = [ { + name: 'd', data: sshbuf.readBuffer() + } ]; + } else if (alg === 'ssh-ed25519') { + privateKeyParts = [ { + name: 'k', data: sshbuf.readBuffer() + } ]; + } else { + throw new Error('Unsupported PPK key type: ' + alg); + } + + key = new PrivateKey({ + type: key.type, + parts: key.parts.concat(privateKeyParts) + }); + } + key.comment = comment; return (key); } +function derivePPK2EncryptionKey(passphrase) { + var hash1 = crypto.createHash('sha1').update(Buffer.concat([ + Buffer.from([0, 0, 0, 0]), + Buffer.from(passphrase) + ])).digest(); + var hash2 = crypto.createHash('sha1').update(Buffer.concat([ + Buffer.from([0, 0, 0, 1]), + Buffer.from(passphrase) + ])).digest(); + return (Buffer.concat([hash1, hash2]).slice(0, 32)); +} + function splitHeader(line) { var idx = line.indexOf(':'); if (idx === -1) diff --git a/lib/private-key.js b/lib/private-key.js index 5600838..570e054 100644 --- a/lib/private-key.js +++ b/lib/private-key.js @@ -33,6 +33,7 @@ formats['ssh-private'] = require('./formats/ssh-private'); formats['openssh'] = formats['ssh-private']; formats['ssh'] = formats['ssh-private']; formats['dnssec'] = require('./formats/dnssec'); +formats['putty'] = require('./formats/putty'); function PrivateKey(opts) { assert.object(opts, 'options'); diff --git a/test/assets/dsa-ppk b/test/assets/dsa-ppk new file mode 100644 index 0000000..188fe6f --- /dev/null +++ b/test/assets/dsa-ppk @@ -0,0 +1,20 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIDPQIBAAKCAQEAm6ofqHnQBzlOXYK2o0o9eZi1YtmHksmdRefKAYpsIvO/OwMP +6fLva+9TkUMdgu+B2n0w2vdbh1Qo1QtwRAiq9CKwY1iuK2CfciytvuYsKfLVTsgw +sy4eXb8d4BSrBStvRVkAKjFVqIcXKBBejr30vVDFK0rN3bIZaTilXAdE66wuW19u +mrFT9tiXKkTxPy2rnOrHE6qcgzD6EbfnWBqXOE3YSBzgOezoPExqkQX35cfVJdVI +zX1iS/iJv7VJnr+4kf0zlcT80JGmjEAv17O/tSbcX88xV7R6t4hBsEuqAYhEWKob +YtlJk66bS6FRpahwSNAcdx9flNCfxkygkk/GywIVAOTwYoGm15HYZFDWNnPwJCWv +i92FAoIBAGyuCYSkZY693yb/2/hMdfrwsX/bNeqBz1Eu+uUlwPEjt/hgA5evvLQA +D+EkRbeUI/k7bmzl+VDOzWQ7z9CbbAbeKz/rFg/kkxXhhyatsRJuGUGYdiQIaaKI +51fk71crGzUVfgaQqpN5bE++ub0lJccKFhoNFjRBqesRXyfklTvYTx1BxCrhVf3r +d5px4mDlM2v6UeCSLb6IEBscJgGzbRuuIeRoKYbSAxc2VnLHZMrvRUMVMu13sQPv +gfWpPWR3spsv+bPqXAxtkd7fpxuRll0wJZLSao8oJgdy1XG8X3q+l6grQv2hqoGk +XJUxPpvnkm30gCYMaqCd17UUrjRBjRkCggEAeCoNAd5nqIRV9sTXtxfcFb2o6VVT +rCXt/MQ3CnK5SxDa/gEOhU8y6IwyE9Y7CN6i8ta/Qt4KZcanXS5ciOT+bGT5Y2qx +HKgx8CcWv/J/GKROMxaEwaLvwT8qvI6Jv/x+3/+KwufaHA1w5ObOHL+UCaHzSuLK +pPRWAbWc2GOZtyfMasmwA5tKzdRJ9VTjS4lVKKOI32AV70hhk7wHIBeRZgrxUw+N +ZnlH5HWKZf2mWemPHhxsglKIczosCmg10vEVuFvIVzeSieV7y6/X/HIsAsjE6IMm +RZDiU9h5rb9FJLrdgGgn6P8XIjJ7e3+P21EL0mi63sRQFQHfLEwA8F3UgQIUJ2Qi +WkIsuhpeOTgyMLX2FWXPHZk= +-----END DSA PRIVATE KEY----- diff --git a/test/assets/dsa-ppk.pub b/test/assets/dsa-ppk.pub deleted file mode 100644 index 3bdb87f..0000000 --- a/test/assets/dsa-ppk.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAAEBALPLp37KKWyxxCtV085ozT7tY1zQimFhPvD+rPO4SSfHquoRM/szwOXAqyavqYggajNyzSN/x5+gLu4p2iTmS0jC0Nf2FB5tyqxBKsrubmhVMZpK+dBLm2V7NTE6fJpGRmpTNCKWPOfdZP7wF0w8oRNaTz1ILjNlXh06zXrp4FU+wv0ums1PemF5Ff7u77vzkxXDsYFOO+btgAFEO8oTBapG1H0ZkcvTzIStCY6SnbzDggPtaqasKLjh4zocvdR9M4E1IIFtMaFSZx19w6ccpzAFD7dqTqNVavSN2SzSzcjMeEdaLiSceof8qu5IcLdrofuQ0ltCVKNFrMm9pZK2kvUAAAAVANmWKeGafd0C0vAgGthSALs1q/q1AAABAQCtHTj9zydZ2VDhHxrge+WeSF/Ix0zUknwDo7luJGgSTb/BZg42W+RIsWo+qFeK6XEzuaqlXIOL7ekBFkDvwOGt1l13T6YF4xH1XvjKg4+YP/U+QMqgiv/+eBodmm14vZqDUD37C1JXMr/vJ+6xDYlvJwwUdmBUcU0PMyw70YHEtWeGuzXbvMDsKLztXQrYJqzjKX7pyf0x2Rj3g7/HSdIssP32Da2lflNs0VPqCWjsG1bDiU8oqdOHhekfM+khqvVNIxmI/6nW/Izax/8ORv0QSmPxFp0FmTaRtNFInLDnOnshXHf5h9+eC4vLmDs2P/65FLfS5WfQMABPTdifsLG6AAABAQCeT7XwWZ5+OMoGYgh2WeTAmHCykXnhnuH0LvyRoeuJq+oX3QJyU/I5L71mjQ1eCqMa/7RYZ3J2ct34ZQ7qiJzgbUgPvKuFuRgf12gn7cCc97Mu/Fo/Mjm0iisYigAR/QbT5uIpIASr5z8JxdNaEgEzhwP3o3+YviXXwEAbN36ZBwLp54MODbz+n5xGqG9avE5i4VCOkP5Q3ng6nnn+kelyaIHsWd498YJEQcs0eKaYlux03/D0hD/q6HLVtob6qjUN7xo0xFcYKQBzkBz0CgQ/CvgfKFOrS8Z/EdS6d6dFB8yKvEXygRPdE9MSepPlfy1d9Vvys8k2fs+Ny72wgg5I dsa-key-20170331 diff --git a/test/assets/dsa-pub.ppk b/test/assets/dsa-pub.ppk index fca1163..eda6e23 100644 --- a/test/assets/dsa-pub.ppk +++ b/test/assets/dsa-pub.ppk @@ -1,22 +1,22 @@ PuTTY-User-Key-File-2: ssh-dss Encryption: none -Comment: dsa-key-20170331 +Comment: dsa-key-20210515 Public-Lines: 18 -AAAAB3NzaC1kc3MAAAEBALPLp37KKWyxxCtV085ozT7tY1zQimFhPvD+rPO4SSfH -quoRM/szwOXAqyavqYggajNyzSN/x5+gLu4p2iTmS0jC0Nf2FB5tyqxBKsrubmhV -MZpK+dBLm2V7NTE6fJpGRmpTNCKWPOfdZP7wF0w8oRNaTz1ILjNlXh06zXrp4FU+ -wv0ums1PemF5Ff7u77vzkxXDsYFOO+btgAFEO8oTBapG1H0ZkcvTzIStCY6SnbzD -ggPtaqasKLjh4zocvdR9M4E1IIFtMaFSZx19w6ccpzAFD7dqTqNVavSN2SzSzcjM -eEdaLiSceof8qu5IcLdrofuQ0ltCVKNFrMm9pZK2kvUAAAAVANmWKeGafd0C0vAg -GthSALs1q/q1AAABAQCtHTj9zydZ2VDhHxrge+WeSF/Ix0zUknwDo7luJGgSTb/B -Zg42W+RIsWo+qFeK6XEzuaqlXIOL7ekBFkDvwOGt1l13T6YF4xH1XvjKg4+YP/U+ -QMqgiv/+eBodmm14vZqDUD37C1JXMr/vJ+6xDYlvJwwUdmBUcU0PMyw70YHEtWeG -uzXbvMDsKLztXQrYJqzjKX7pyf0x2Rj3g7/HSdIssP32Da2lflNs0VPqCWjsG1bD -iU8oqdOHhekfM+khqvVNIxmI/6nW/Izax/8ORv0QSmPxFp0FmTaRtNFInLDnOnsh -XHf5h9+eC4vLmDs2P/65FLfS5WfQMABPTdifsLG6AAABAQCeT7XwWZ5+OMoGYgh2 -WeTAmHCykXnhnuH0LvyRoeuJq+oX3QJyU/I5L71mjQ1eCqMa/7RYZ3J2ct34ZQ7q -iJzgbUgPvKuFuRgf12gn7cCc97Mu/Fo/Mjm0iisYigAR/QbT5uIpIASr5z8JxdNa -EgEzhwP3o3+YviXXwEAbN36ZBwLp54MODbz+n5xGqG9avE5i4VCOkP5Q3ng6nnn+ -kelyaIHsWd498YJEQcs0eKaYlux03/D0hD/q6HLVtob6qjUN7xo0xFcYKQBzkBz0 -CgQ/CvgfKFOrS8Z/EdS6d6dFB8yKvEXygRPdE9MSepPlfy1d9Vvys8k2fs+Ny72w -gg5I +AAAAB3NzaC1kc3MAAAEBAJuqH6h50Ac5Tl2CtqNKPXmYtWLZh5LJnUXnygGKbCLz +vzsDD+ny72vvU5FDHYLvgdp9MNr3W4dUKNULcEQIqvQisGNYritgn3Isrb7mLCny +1U7IMLMuHl2/HeAUqwUrb0VZACoxVaiHFygQXo699L1QxStKzd2yGWk4pVwHROus +LltfbpqxU/bYlypE8T8tq5zqxxOqnIMw+hG351galzhN2Egc4Dns6DxMapEF9+XH +1SXVSM19Ykv4ib+1SZ6/uJH9M5XE/NCRpoxAL9ezv7Um3F/PMVe0ereIQbBLqgGI +RFiqG2LZSZOum0uhUaWocEjQHHcfX5TQn8ZMoJJPxssAAAAVAOTwYoGm15HYZFDW +NnPwJCWvi92FAAABAGyuCYSkZY693yb/2/hMdfrwsX/bNeqBz1Eu+uUlwPEjt/hg +A5evvLQAD+EkRbeUI/k7bmzl+VDOzWQ7z9CbbAbeKz/rFg/kkxXhhyatsRJuGUGY +diQIaaKI51fk71crGzUVfgaQqpN5bE++ub0lJccKFhoNFjRBqesRXyfklTvYTx1B +xCrhVf3rd5px4mDlM2v6UeCSLb6IEBscJgGzbRuuIeRoKYbSAxc2VnLHZMrvRUMV +Mu13sQPvgfWpPWR3spsv+bPqXAxtkd7fpxuRll0wJZLSao8oJgdy1XG8X3q+l6gr +Qv2hqoGkXJUxPpvnkm30gCYMaqCd17UUrjRBjRkAAAEAeCoNAd5nqIRV9sTXtxfc +Fb2o6VVTrCXt/MQ3CnK5SxDa/gEOhU8y6IwyE9Y7CN6i8ta/Qt4KZcanXS5ciOT+ +bGT5Y2qxHKgx8CcWv/J/GKROMxaEwaLvwT8qvI6Jv/x+3/+KwufaHA1w5ObOHL+U +CaHzSuLKpPRWAbWc2GOZtyfMasmwA5tKzdRJ9VTjS4lVKKOI32AV70hhk7wHIBeR +ZgrxUw+NZnlH5HWKZf2mWemPHhxsglKIczosCmg10vEVuFvIVzeSieV7y6/X/HIs +AsjE6IMmRZDiU9h5rb9FJLrdgGgn6P8XIjJ7e3+P21EL0mi63sRQFQHfLEwA8F3U +gQ== diff --git a/test/assets/dsa.ppk b/test/assets/dsa.ppk index 510a10b..bc24c33 100644 --- a/test/assets/dsa.ppk +++ b/test/assets/dsa.ppk @@ -1,25 +1,25 @@ PuTTY-User-Key-File-2: ssh-dss Encryption: aes256-cbc -Comment: dsa-key-20170331 +Comment: dsa-key-20210515 Public-Lines: 18 -AAAAB3NzaC1kc3MAAAEBALPLp37KKWyxxCtV085ozT7tY1zQimFhPvD+rPO4SSfH -quoRM/szwOXAqyavqYggajNyzSN/x5+gLu4p2iTmS0jC0Nf2FB5tyqxBKsrubmhV -MZpK+dBLm2V7NTE6fJpGRmpTNCKWPOfdZP7wF0w8oRNaTz1ILjNlXh06zXrp4FU+ -wv0ums1PemF5Ff7u77vzkxXDsYFOO+btgAFEO8oTBapG1H0ZkcvTzIStCY6SnbzD -ggPtaqasKLjh4zocvdR9M4E1IIFtMaFSZx19w6ccpzAFD7dqTqNVavSN2SzSzcjM -eEdaLiSceof8qu5IcLdrofuQ0ltCVKNFrMm9pZK2kvUAAAAVANmWKeGafd0C0vAg -GthSALs1q/q1AAABAQCtHTj9zydZ2VDhHxrge+WeSF/Ix0zUknwDo7luJGgSTb/B -Zg42W+RIsWo+qFeK6XEzuaqlXIOL7ekBFkDvwOGt1l13T6YF4xH1XvjKg4+YP/U+ -QMqgiv/+eBodmm14vZqDUD37C1JXMr/vJ+6xDYlvJwwUdmBUcU0PMyw70YHEtWeG -uzXbvMDsKLztXQrYJqzjKX7pyf0x2Rj3g7/HSdIssP32Da2lflNs0VPqCWjsG1bD -iU8oqdOHhekfM+khqvVNIxmI/6nW/Izax/8ORv0QSmPxFp0FmTaRtNFInLDnOnsh -XHf5h9+eC4vLmDs2P/65FLfS5WfQMABPTdifsLG6AAABAQCeT7XwWZ5+OMoGYgh2 -WeTAmHCykXnhnuH0LvyRoeuJq+oX3QJyU/I5L71mjQ1eCqMa/7RYZ3J2ct34ZQ7q -iJzgbUgPvKuFuRgf12gn7cCc97Mu/Fo/Mjm0iisYigAR/QbT5uIpIASr5z8JxdNa -EgEzhwP3o3+YviXXwEAbN36ZBwLp54MODbz+n5xGqG9avE5i4VCOkP5Q3ng6nnn+ -kelyaIHsWd498YJEQcs0eKaYlux03/D0hD/q6HLVtob6qjUN7xo0xFcYKQBzkBz0 -CgQ/CvgfKFOrS8Z/EdS6d6dFB8yKvEXygRPdE9MSepPlfy1d9Vvys8k2fs+Ny72w -gg5I +AAAAB3NzaC1kc3MAAAEBAJuqH6h50Ac5Tl2CtqNKPXmYtWLZh5LJnUXnygGKbCLz +vzsDD+ny72vvU5FDHYLvgdp9MNr3W4dUKNULcEQIqvQisGNYritgn3Isrb7mLCny +1U7IMLMuHl2/HeAUqwUrb0VZACoxVaiHFygQXo699L1QxStKzd2yGWk4pVwHROus +LltfbpqxU/bYlypE8T8tq5zqxxOqnIMw+hG351galzhN2Egc4Dns6DxMapEF9+XH +1SXVSM19Ykv4ib+1SZ6/uJH9M5XE/NCRpoxAL9ezv7Um3F/PMVe0ereIQbBLqgGI +RFiqG2LZSZOum0uhUaWocEjQHHcfX5TQn8ZMoJJPxssAAAAVAOTwYoGm15HYZFDW +NnPwJCWvi92FAAABAGyuCYSkZY693yb/2/hMdfrwsX/bNeqBz1Eu+uUlwPEjt/hg +A5evvLQAD+EkRbeUI/k7bmzl+VDOzWQ7z9CbbAbeKz/rFg/kkxXhhyatsRJuGUGY +diQIaaKI51fk71crGzUVfgaQqpN5bE++ub0lJccKFhoNFjRBqesRXyfklTvYTx1B +xCrhVf3rd5px4mDlM2v6UeCSLb6IEBscJgGzbRuuIeRoKYbSAxc2VnLHZMrvRUMV +Mu13sQPvgfWpPWR3spsv+bPqXAxtkd7fpxuRll0wJZLSao8oJgdy1XG8X3q+l6gr +Qv2hqoGkXJUxPpvnkm30gCYMaqCd17UUrjRBjRkAAAEAeCoNAd5nqIRV9sTXtxfc +Fb2o6VVTrCXt/MQ3CnK5SxDa/gEOhU8y6IwyE9Y7CN6i8ta/Qt4KZcanXS5ciOT+ +bGT5Y2qxHKgx8CcWv/J/GKROMxaEwaLvwT8qvI6Jv/x+3/+KwufaHA1w5ObOHL+U +CaHzSuLKpPRWAbWc2GOZtyfMasmwA5tKzdRJ9VTjS4lVKKOI32AV70hhk7wHIBeR +ZgrxUw+NZnlH5HWKZf2mWemPHhxsglKIczosCmg10vEVuFvIVzeSieV7y6/X/HIs +AsjE6IMmRZDiU9h5rb9FJLrdgGgn6P8XIjJ7e3+P21EL0mi63sRQFQHfLEwA8F3U +gQ== Private-Lines: 1 -KSl/bN/cgkBjVRhd91zBbTlSPNqRwQJ5xDF4qrehUtQ= -Private-MAC: 3ab460bd517d8f4747f837a37710f88ad95be6ea +ony1aHwujzT0bx1MCaH55NpCy6K/L+/rKAeb5CBF/D4= +Private-MAC: 0e1508506fff981e5042d029429bfcb5765e80ba diff --git a/test/assets/ecdsa-ppk b/test/assets/ecdsa-ppk new file mode 100644 index 0000000..db6c1d9 --- /dev/null +++ b/test/assets/ecdsa-ppk @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIH6319TQpT2OtWoyurNrC8t8RTMnKGkuF7Hg+iRAHaO5oAoGCCqGSM49 +AwEHoUQDQgAEKK8I4bJpFBon3SvTLM+ZMnXZIHgUHluna7SQP/XlrwGkNweyjUYg +iMHJjYbrnkdH1BeQ4MaZNM8yFVmnhQoLAw== +-----END EC PRIVATE KEY----- diff --git a/test/assets/ecdsa.ppk b/test/assets/ecdsa.ppk new file mode 100644 index 0000000..4dc85a5 --- /dev/null +++ b/test/assets/ecdsa.ppk @@ -0,0 +1,10 @@ +PuTTY-User-Key-File-2: ecdsa-sha2-nistp256 +Encryption: aes256-cbc +Comment: ecdsa-key-20210515 +Public-Lines: 3 +AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCivCOGyaRQa +J90r0yzPmTJ12SB4FB5bp2u0kD/15a8BpDcHso1GIIjByY2G655HR9QXkODGmTTP +MhVZp4UKCwM= +Private-Lines: 1 +MW4fcSm+yRUR/19z3GrDV0dbjweegsEoWNIswwALYas8sV0l4S2k+b41qXuflP9N +Private-MAC: 18146097d09025727b6facc1102aae201bd18364 diff --git a/test/assets/ed25519-ppk b/test/assets/ed25519-ppk new file mode 100644 index 0000000..881b393 --- /dev/null +++ b/test/assets/ed25519-ppk @@ -0,0 +1,4 @@ +-----BEGIN EdDSA PRIVATE KEY----- +MFECAQEEIJ4V2rGkAcGHBQnspmDrWJ9yncXAhJRi4NeE2FsQb0xMoAUGAytlcKEj +AyEAVMkgHj6fUvLKiElOBtIMY27CldSJoLaTy0gmKs9rbIM= +-----END EdDSA PRIVATE KEY----- diff --git a/test/assets/ed25519.ppk b/test/assets/ed25519.ppk new file mode 100644 index 0000000..3e2ddd5 --- /dev/null +++ b/test/assets/ed25519.ppk @@ -0,0 +1,9 @@ +PuTTY-User-Key-File-2: ssh-ed25519 +Encryption: aes256-cbc +Comment: ed25519-key-20210515 +Public-Lines: 2 +AAAAC3NzaC1lZDI1NTE5AAAAIFTJIB4+n1LyyohJTgbSDGNuwpXUiaC2k8tIJirP +a2yD +Private-Lines: 1 +Sth4e+fEa1lawlgah31ocn4Imf2pnocHG7jArPG2UxWNwmm7lUYm/SLfb5spucPt +Private-MAC: aeec318aa251a446fb1d6f18d6288a264f3d0b41 diff --git a/test/assets/ppk3 b/test/assets/ppk3 new file mode 100644 index 0000000..b88982d --- /dev/null +++ b/test/assets/ppk3 @@ -0,0 +1,26 @@ +PuTTY-User-Key-File-3: ssh-rsa +Encryption: none +Comment: rsa-key-20211214 +Public-Lines: 6 +AAAAB3NzaC1yc2EAAAADAQABAAABAQCQWPBUsyVmi5vl8myEQ91IP2JroWP1N2NR +xvFeIcGgtPSwq/7MIq2Vis8s2JlpBjFY2aDDGSlrWrh4Ryqs9NnvueLgeWjgD8wv +3qnYgv4pdu6k7HLrE5J22vQ6M8tFjpPDAVS+mfFIe9+RutO1eimhuh824ErTPKPT +LdBrheuZpUIaWl45Kd529V6CO0+b0/U/7zVfC/uKcHxDZ4RK2AkKOYMROb93B0qY +6n4t0tjkzFDJvqgMa7FoIwLkczyGSbpmKh39pvoMOyQB50WFSXbPuNscubGcOJAa +1SARXLLQh6UB9AiJqt+bk6r4OQyiXeKkk5u9lXNnxk1aMQQW46hh +Private-Lines: 14 +AAABACnnyA2u3ILCsQW2tU5IrWsWC6qXdf9wjwLksJnVTvMq1YacyCHXR3GMlMy+ +LPtScu0KcSNyoJWsBrXUY01G4CY6XuUwGgRCUdLr338duE+tWWbDxjD8w56BvjlP +ZAnTdI4+Sq3y3xtd6u/RvziGOKPc9sblopNknWLngARXIqi94TVawRHNyrnCNNn2 +gWfi62ZxY2rLOHD5hJv2xFh84eNEdf94nnWkbaJ/aZmR6d8VdBcJCiK/60CgKYlO +ZuRHdEC3QCqa/S1Ya8m9egT90jUf6vmxb/GkK4Y0VigVLFdtaT7cJ8W6gbCmTaa2 +4iax3M6y9AR2sQLpNNhB1gf3oAEAAACBAO04zQFxbgozu7m58RIc87pm8NeQ5UmF +hCV/K8Ja9QpUzztmoouo6r43itW+6DWmIYLqjlcV7zK6W4aTQ4/fSREiDHPhG7wG +NloXL+jsyAuu7FqfQVKVbh8aIg4uvKpg+nUV+YYgOKcucriKMwdpP8dy1D2Ti5jn +rVZNfmCAtLLhAAAAgQCbxhO4l2rtzodMnwSTyt3s17D5PPXPKSU03cDFsAnSYo2K +6q7pVxMBPYqo4KWlhM4fN0ByY3kobFc2cAbLbck+x12C559LJr9RP3DHUQ9oxjB5 +JhYLgjN1JFS3dc7THi1nTM+NO0OQuytbeY+aNJ+UXW0zRtK/bwiGpsdGiFslgQAA +AIAeH7hALcDaAiZs0Jsb4/39zuGlb27r+KesxkYgIy7DaAOvQyZaT3X0JrAwqRqs +UJl+AS39VpL7XQFIbICJyhPbHHO3IGCUKhOz0BCqpHjnn9/ViRuNnrr1UTgDS0qc +tw/JH+KlK94nGmMEjBUUJpXJqjAXR7x8feoTqjtvijQtjA== +Private-MAC: a172468747b16c488815cb90b4359fe61d262c9a9329f60cabf6763deb638d8e diff --git a/test/assets/ppk3.pem b/test/assets/ppk3.pem new file mode 100644 index 0000000..cec8d32 --- /dev/null +++ b/test/assets/ppk3.pem @@ -0,0 +1,22 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIDogIBAAKCAQEAkFjwVLMlZoub5fJshEPdSD9ia6Fj9TdjUcbxXiHBoLT0sKv+ +zCKtlYrPLNiZaQYxWNmgwxkpa1q4eEcqrPTZ77ni4Hlo4A/ML96p2IL+KXbupOxy +6xOSdtr0OjPLRY6TwwFUvpnxSHvfkbrTtXopobofNuBK0zyj0y3Qa4XrmaVCGlpe +OSnedvVegjtPm9P1P+81Xwv7inB8Q2eEStgJCjmDETm/dwdKmOp+LdLY5MxQyb6o +DGuxaCMC5HM8hkm6Ziod/ab6DDskAedFhUl2z7jbHLmxnDiQGtUgEVyy0IelAfQI +iarfm5Oq+DkMol3ipJObvZVzZ8ZNWjEEFuOoYQIDAQABAoIBACnnyA2u3ILCsQW2 +tU5IrWsWC6qXdf9wjwLksJnVTvMq1YacyCHXR3GMlMy+LPtScu0KcSNyoJWsBrXU +Y01G4CY6XuUwGgRCUdLr338duE+tWWbDxjD8w56BvjlPZAnTdI4+Sq3y3xtd6u/R +vziGOKPc9sblopNknWLngARXIqi94TVawRHNyrnCNNn2gWfi62ZxY2rLOHD5hJv2 +xFh84eNEdf94nnWkbaJ/aZmR6d8VdBcJCiK/60CgKYlOZuRHdEC3QCqa/S1Ya8m9 +egT90jUf6vmxb/GkK4Y0VigVLFdtaT7cJ8W6gbCmTaa24iax3M6y9AR2sQLpNNhB +1gf3oAECgYEA7TjNAXFuCjO7ubnxEhzzumbw15DlSYWEJX8rwlr1ClTPO2aii6jq +vjeK1b7oNaYhguqOVxXvMrpbhpNDj99JESIMc+EbvAY2Whcv6OzIC67sWp9BUpVu +HxoiDi68qmD6dRX5hiA4py5yuIozB2k/x3LUPZOLmOetVk1+YIC0suECgYEAm8YT +uJdq7c6HTJ8Ek8rd7New+Tz1zyklNN3AxbAJ0mKNiuqu6VcTAT2KqOClpYTOHzdA +cmN5KGxXNnAGy23JPsddguefSya/UT9wx1EPaMYweSYWC4IzdSRUt3XO0x4tZ0zP +jTtDkLsrW3mPmjSflF1tM0bSv28IhqbHRohbJYECAQACAQACgYAeH7hALcDaAiZs +0Jsb4/39zuGlb27r+KesxkYgIy7DaAOvQyZaT3X0JrAwqRqsUJl+AS39VpL7XQFI +bICJyhPbHHO3IGCUKhOz0BCqpHjnn9/ViRuNnrr1UTgDS0qctw/JH+KlK94nGmME +jBUUJpXJqjAXR7x8feoTqjtvijQtjA== +-----END RSA PRIVATE KEY----- diff --git a/test/assets/rsa-ppk b/test/assets/rsa-ppk new file mode 100644 index 0000000..878a64b --- /dev/null +++ b/test/assets/rsa-ppk @@ -0,0 +1,22 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIDogIBAAKCAQEAzCyvaBRhKzRC/Hpi+OnF+7oCw98gJolGQ4lDfKGBMkrtNU16 +AtL9FfgiQA+f84kpt8YVfYGXhvPDPOAjnZADac3KYdHniWfV3/m9qZomkRTf4jIa +cOICnDqiVMsqAIOYrB1rfDyp5bm9bGuY+w/mpgAWKfmXwbnjNvD95345WkvD+Jlr +VduMrr1ovQYApmmhj5HFkC5XNVJLjklqHlOJzwyWUlrk6ROx+75Ufv+4wBz3Gf0l +iRPjUQesoCutI+RheUDfRbI58UtXIXMJAUUwMHWt2Rc0LjK+lrwmoMN/WRt8GfX4 +Cj/TSnVHI/QcyH06kD+v1Sdt/8kJlOmARWmyyQIBJQKCAQEApYwD19ksMN5EJqhr +7GqE2fDD+MLAHz7fBlOegLpNFAVmYpHYjKsSZNcHA4JKVsI9gD++ZcMFPPz/KnCL +lIKa+9dKJczJkgEp898/1Z+U5FYdT54+874roURMRMBnPq/jkni4A94o48cIShIN +VfE3jYOHl6fHJ3QgAwiWhFiBh3pAcNe6xcUyhHP8E6fTNVXaXBlgY5xYQ42VybyQ +4ogEYIxwwhdTey4a/3MGVGS7YIj3j/JPiiKD2JRrxrydhG1ox2P8iypGp2gIFzZb +NOWjqFZl2i8/kEn4P8vwLpP6iMBOkgpC59tghSo4/u8kt8h6cXDptnJKX0vDN210 +8q0drQKBgQDwcB2N+948I0Oaueqwa4oJadIFZw21Hr/3EO3oxiKOysjVnfN7TZOx +PhWIdiJI7SpfJRMtMKfyUPaDiZaeKxgvx2wedNg6J7OTlNX2tTV+T7Bt0YWspyq5 +a1UWi1fAOLL43ZkuzancRt8kO0D33n1Ic2r1E+yqJ3TCsYTv0OYm6QKBgQDZY7YQ +mUXWgbeOlYgQAaBgK6Bz8op5fv1O83t5Ud6PN9rPPH3X+wtn+hJmXINVho3vKcen +UDBOY+KkKgHEKs3KET/WJTbs6g7sxVF/rPR5GbAGrayW/73bh2MBdZMbM3tViD8Q +UdQzLCZUFK5Vfsz0sw28pHqbUbsaY0yAOCWA4QIBAAIBAAKBgQCzZULNTlJ0NJ9q +1Z29r4jVTgyNIg/VMhYKEqSyM4tDGvUJqKc5AIe+AMKKa4Hgx7A/t+S+zr0P9Os/ +bfcqQM3SlqRmKcwY1pcliuyYDnGkajHl2bDnImFl/fq7wwlCoUfaqoK/v8kXh4vi +MG9gMnV0xuW+DUQ/m7Ag5QhnMuNREg== +-----END RSA PRIVATE KEY----- diff --git a/test/assets/rsa.ppk b/test/assets/rsa.ppk index a19bf83..77649bd 100644 --- a/test/assets/rsa.ppk +++ b/test/assets/rsa.ppk @@ -1,26 +1,26 @@ PuTTY-User-Key-File-2: ssh-rsa Encryption: aes256-cbc -Comment: rsa-key-20170331 +Comment: rsa-key-20210515 Public-Lines: 6 -AAAAB3NzaC1yc2EAAAABJQAAAQEAsJb8crG6hSSizpKs8EQip90n+n4MKs6qYKIt -r4X8EeBhKMbQNXGbLC617Ui0cVQMF8nfEGe61/Fc0uQOWJdEk2ANe6rtcaFPTwYH -LyPznd28c9xfBifqksdBjqH+Svr57MBqmivQi3gTIXeIlGYyXhKh9U8J2WDIpMks -hE1UmsqvJgMjoqNVWG/iU+t4GeKxdDd4TGIHiZU6JfGf777pAB2+Uhi7PrSvs7Ov -oetgNW7LFsPiA8zbwfj5jkVQ2ycHoAOHMuthB3bkNetL+A6V6pkfDLTVd9g0SiPF -K03ut1XIw+FtxO5ioEfy5XvwkIPbAl2vInfxL0EacWFkXq08ew== +AAAAB3NzaC1yc2EAAAABJQAAAQEAzCyvaBRhKzRC/Hpi+OnF+7oCw98gJolGQ4lD +fKGBMkrtNU16AtL9FfgiQA+f84kpt8YVfYGXhvPDPOAjnZADac3KYdHniWfV3/m9 +qZomkRTf4jIacOICnDqiVMsqAIOYrB1rfDyp5bm9bGuY+w/mpgAWKfmXwbnjNvD9 +5345WkvD+JlrVduMrr1ovQYApmmhj5HFkC5XNVJLjklqHlOJzwyWUlrk6ROx+75U +fv+4wBz3Gf0liRPjUQesoCutI+RheUDfRbI58UtXIXMJAUUwMHWt2Rc0LjK+lrwm +oMN/WRt8GfX4Cj/TSnVHI/QcyH06kD+v1Sdt/8kJlOmARWmyyQ== Private-Lines: 14 -lfdred2syPlQV1MrIG+3uAKVIrd8Wlprhxyco0A3LEbEjaUJOMaRY4GG+47MUdfG -YKqtH1zWuvpBrlfmLiUySL2j4DustFvMkLD9aFI4IFUPPCbV0ujuQh1rFQuutzDj -dmOFdQAcwV0/clB2ewz/tX5x0GPQq71xrLHq4qQLepaDbZFIhF+S6K+opXiSJPc6 -YG6SJKMBj+jshFrHeONN+MLTCPxDb/Ulrh3Fl5no1xLjjZEtO/TETeKyeM3jUAu2 -oNn8WI9MP2wEGgp2Nux8759BveUr4zH71lS9OKagG1ipxMkyikrgAZpXbxTVFXsq -m+5RkZuvd9smYVJl3S2T1c/YcS5SaSaC4FTYEOw70N68Mw2nOQEWpXkdnxqUMdbp -o209XxOQdYsbBi3+FWfcY/jr846XstkRx2wj5PfGFn/ULIoaMNIpYHgP2JgSsz+G -rX5ZXktpCzHRBfhudqyOAzvlWqyQS5+hBpigqupUbrRHJKmuGNYkhay9W/Ka80pX -+K7yom1k6JD8lK+GA+AvU+v2pxKMsvoxVDBgJUfvg4Su8wVyPj8g01DSvrM9Ld4X -1nXbA+kEijokalDsxhcp6ZjYWBFwMn+kBZ7ztBlwKf5gnoMa9A917mJiUNy1B+t8 -CwYuBNilNUWSrWCcoG29c9HPyz8QVkFPfMpqhX3W43G2a3pRi2CZzwEHV+te4TDz -pmpU2yObRH93nWVnFn91onKL0rHPEI4613e7Nhb8R1dhXtJZoLPbjdLJlmWUgZa/ -VDfhatovJ7XzD4WRaamJaevK6LUnmULDZRkzU9fJJBLp76BJvbENiQ6GANGp4i2h -bJ0sbiWMFEnKTFGpcIVLZI11xLJ7H9S6TrDJFVhVSGB114Dj0TjIdA8FyOOik77o -Private-MAC: e528058a4a0851024975d88a0b012bb8b40607b0 +AUFX4NAp+CJWaP65DnQgqkV8MT0RllvpFv6nvsL8bhna1T9zjqudBgljeCGkAQgX +vcEOOYgQA+HuJ4TJGp/qrVPms9BO3uNXwj9JEURLqLj71Dac+3VqdMUIjC/NjcAZ +S5wJMLUIYvUBoZd8sk1BAhMa2eS7QPgbZlarbMtlBoz+2JO2AGJWButrgWE6rH1L +BegEQVe9RoCoweV8MqPKhtE6C6IjvWALVmJ2YyKSoteQm2M9CHBQFGI0jg2ak1nN +S0J9A1kT4+5e0TgpakbUcqlArM0C/0zz3jpKYxNicZ+ZTXV5pQzuUfmya3I7oPww +sc+o/lm0loEMB9JbQ3g8K84EacIejb5RwxQOpDmbHR2THyR01Qb0Z5EFBHnQXI8a +H9sbou1+ZgMWJT7RX/oNQjmL6e/sKA19zDgs11RZtZnQ2WWTFnFRFxD3ZZtKHPMW +5Zzm04U3TqiJsm2oZZcpDdWEtiNSOHlyg3hwHpKRQAhGGX/JNlcQwnDJDfb2CL34 +AiBt70+sBYuIIcOL2A9MqSP4TMnNuHQSYKfoKDDgYUA+IH+ryTZuOTRMJWvmp/f9 +pZ7z/Cln6XI/ZnAu5vAHXo41G+fheKAoCNJrC7NyNnmDrD+WyoA+TfX+pGJGiBZX +szhNXS4dqquCZWrzu3N2jzgYypkF4WbQmiLsxGXyU7NEspdZAl0Yr1846eQE/SZs +KxucgAIcct917X9qZ1JfABc3rNPCKJiHRMTFnnS8zh6PDSmx75WQPQVrsQCkOEIK +yyflT9pSPGNHKswcWZuXo7mRcW17sNefYW4fqv1G5M0Ua2MWtTJzXABFW7AzVAhh +QoipnjNL7Q55kME5WM9CFprfzIgWua6b4J9AGDNdDtcwOQS73EuW9cdBDUrbBe90 +Private-MAC: 4e5876341d24fc7c49290d1618f28f894699c557 diff --git a/test/putty.js b/test/putty.js index 28ab890..4ed5e06 100644 --- a/test/putty.js +++ b/test/putty.js @@ -7,25 +7,33 @@ var sshpk = require('../lib/index'); var testDir = path.join(__dirname, 'assets'); -var PUTTY_DSA, PUTTY_DSA_PUB, PUTTY_RSA, PUTTY_DSA_SSH, PUTTY_DSA_LONG; +var PUTTY_DSA, PUTTY_DSA_PUB, PUTTY_RSA, PUTTY_RSA_SSH, PUTTY_DSA_SSH, PUTTY_DSA_LONG, + PUTTY_ECDSA, PUTTY_ECDSA_SSH, PUTTY_ED25519, PUTTY_ED25519_SSH, PUTTY_PPK3, PUTTY_PPK3_PEM; test('setup', function (t) { PUTTY_DSA = fs.readFileSync(path.join(testDir, 'dsa.ppk')); PUTTY_DSA_PUB = fs.readFileSync(path.join(testDir, 'dsa-pub.ppk')); PUTTY_RSA = fs.readFileSync(path.join(testDir, 'rsa.ppk')); - PUTTY_DSA_SSH = fs.readFileSync(path.join(testDir, 'dsa-ppk.pub')); + PUTTY_RSA_SSH = fs.readFileSync(path.join(testDir, 'rsa-ppk')); + PUTTY_DSA_SSH = fs.readFileSync(path.join(testDir, 'dsa-ppk')); PUTTY_DSA_LONG = fs.readFileSync(path.join(testDir, 'dsa-pub-err.ppk')); + PUTTY_ECDSA = fs.readFileSync(path.join(testDir, 'ecdsa.ppk')); + PUTTY_ECDSA_SSH = fs.readFileSync(path.join(testDir, 'ecdsa-ppk')); + PUTTY_ED25519 = fs.readFileSync(path.join(testDir, 'ed25519.ppk')); + PUTTY_ED25519_SSH = fs.readFileSync(path.join(testDir, 'ed25519-ppk')); + PUTTY_PPK3 = fs.readFileSync(path.join(testDir, 'ppk3')); + PUTTY_PPK3_PEM = fs.readFileSync(path.join(testDir, 'ppk3.pem')); t.end(); }); test('parse DSA ppk file', function (t) { - var k = sshpk.parseKey(PUTTY_DSA, 'putty'); + var k = sshpk.parsePrivateKey(PUTTY_DSA, 'putty', { passphrase: 'foobar' }); t.strictEqual(k.type, 'dsa'); t.strictEqual(k.fingerprint('sha256').toString(), - 'SHA256:wWAQNw7Px2Hymk7kimFL35jzdLqRt9V9hB5RH20YX8s'); - t.strictEqual(k.comment, 'dsa-key-20170331'); - var pub = k.toString('ssh'); - t.strictEqual(pub, PUTTY_DSA_SSH.toString('ascii').trim()); + 'SHA256:l95D4D6waUPH49RvkOLHWzwGSNKqg3GZx5f28UdcmDo'); + t.strictEqual(k.comment, 'dsa-key-20210515'); + var priv = k.toString('pem').trim(); + t.strictEqual(priv, PUTTY_DSA_SSH.toString('ascii').trim()); t.end(); }); @@ -33,17 +41,20 @@ test('parse DSA ppk file pub-only truncated', function (t) { var k = sshpk.parseKey(PUTTY_DSA_PUB, 'putty'); t.strictEqual(k.type, 'dsa'); t.strictEqual(k.fingerprint('sha256').toString(), - 'SHA256:wWAQNw7Px2Hymk7kimFL35jzdLqRt9V9hB5RH20YX8s'); - t.strictEqual(k.comment, 'dsa-key-20170331'); + 'SHA256:l95D4D6waUPH49RvkOLHWzwGSNKqg3GZx5f28UdcmDo'); + t.strictEqual(k.comment, 'dsa-key-20210515'); t.end(); }); test('parse RSA ppk file', function (t) { - var k = sshpk.parseKey(PUTTY_RSA, 'putty'); + var k = sshpk.parsePrivateKey(PUTTY_RSA, 'putty', { passphrase: 'foobar' }); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), - 'SHA256:WqDr0IdKUPtbitHUtWGGsA/xV/JhxPbVJG+E0SLWEig'); - t.strictEqual(k.comment, 'rsa-key-20170331'); + 'SHA256:DavVLu91hTy2jkSMKbb6maid8kpoCOP5YkB4Y3UX+dQ'); + t.strictEqual(k.comment, 'rsa-key-20210515'); + + var priv = k.toString('pem').trim(); + t.strictEqual(priv, PUTTY_RSA_SSH.toString('ascii').trim()); t.end(); }); @@ -63,14 +74,49 @@ test('parse garbage as putty', function (t) { }); test('parse RSA ppk file with auto', function (t) { - var k = sshpk.parseKey(PUTTY_RSA, 'auto'); + var k = sshpk.parseKey(PUTTY_RSA, 'auto', { passphrase: 'foobar' }); t.strictEqual(k.type, 'rsa'); t.end(); }); test('generate dsa', function (t) { var k = sshpk.parseKey(PUTTY_DSA_SSH); + k.comment = 'dsa-key-20210515' var ppk = k.toString('putty'); t.strictEqual(ppk, PUTTY_DSA_PUB.toString('ascii')); t.end(); }); + +test('parse ECDSA ppk file', function (t) { + var k = sshpk.parsePrivateKey(PUTTY_ECDSA, 'putty', { passphrase: 'foobar' }); + t.strictEqual(k.type, 'ecdsa'); + t.strictEqual(k.fingerprint('sha256').toString(), + 'SHA256:KlA2NZLpY9cl/HatiN1c5wuzAv4CfpbjH0lHDa+oEKI'); + t.strictEqual(k.comment, 'ecdsa-key-20210515'); + var priv = k.toString('pem').trim(); + t.strictEqual(priv, PUTTY_ECDSA_SSH.toString('ascii').trim()); + t.end(); +}); + +test('parse Ed25519 ppk file', function (t) { + var k = sshpk.parsePrivateKey(PUTTY_ED25519, 'putty', { passphrase: 'foobar' }); + t.strictEqual(k.type, 'ed25519'); + t.strictEqual(k.fingerprint('sha256').toString(), + 'SHA256:b+JitNJGr/mdtSuCZ+qBtFcixd8OrUBhc72b9DjGyJw'); + t.strictEqual(k.comment, 'ed25519-key-20210515'); + var priv = k.toString('pem').trim(); + t.strictEqual(priv, PUTTY_ED25519_SSH.toString('ascii').trim()); + t.end(); +}); + +test('parse PPK3 file', function (t) { + var k = sshpk.parsePrivateKey(PUTTY_PPK3, 'putty'); + t.strictEqual(k.type, 'rsa'); + t.strictEqual(k.fingerprint('sha256').toString(), + 'SHA256:JSIhH7DnsQdxQtE/NnqIAFFIL7NSJ9LJDwLgC6g4xfU'); + t.strictEqual(k.comment, 'rsa-key-20211214'); + + var priv = k.toString('pem').trim(); + t.strictEqual(priv, PUTTY_PPK3_PEM.toString('ascii').trim()); + t.end(); +});