source: trip-planner-front/node_modules/sshpk/lib/formats/ssh-private.js@ b738035

Last change on this file since b738035 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.8 KB
Line 
1// Copyright 2015 Joyent, Inc.
2
3module.exports = {
4 read: read,
5 readSSHPrivate: readSSHPrivate,
6 write: write
7};
8
9var assert = require('assert-plus');
10var asn1 = require('asn1');
11var Buffer = require('safer-buffer').Buffer;
12var algs = require('../algs');
13var utils = require('../utils');
14var crypto = require('crypto');
15
16var Key = require('../key');
17var PrivateKey = require('../private-key');
18var pem = require('./pem');
19var rfc4253 = require('./rfc4253');
20var SSHBuffer = require('../ssh-buffer');
21var errors = require('../errors');
22
23var bcrypt;
24
25function read(buf, options) {
26 return (pem.read(buf, options));
27}
28
29var MAGIC = 'openssh-key-v1';
30
31function readSSHPrivate(type, buf, options) {
32 buf = new SSHBuffer({buffer: buf});
33
34 var magic = buf.readCString();
35 assert.strictEqual(magic, MAGIC, 'bad magic string');
36
37 var cipher = buf.readString();
38 var kdf = buf.readString();
39 var kdfOpts = buf.readBuffer();
40
41 var nkeys = buf.readInt();
42 if (nkeys !== 1) {
43 throw (new Error('OpenSSH-format key file contains ' +
44 'multiple keys: this is unsupported.'));
45 }
46
47 var pubKey = buf.readBuffer();
48
49 if (type === 'public') {
50 assert.ok(buf.atEnd(), 'excess bytes left after key');
51 return (rfc4253.read(pubKey));
52 }
53
54 var privKeyBlob = buf.readBuffer();
55 assert.ok(buf.atEnd(), 'excess bytes left after key');
56
57 var kdfOptsBuf = new SSHBuffer({ buffer: kdfOpts });
58 switch (kdf) {
59 case 'none':
60 if (cipher !== 'none') {
61 throw (new Error('OpenSSH-format key uses KDF "none" ' +
62 'but specifies a cipher other than "none"'));
63 }
64 break;
65 case 'bcrypt':
66 var salt = kdfOptsBuf.readBuffer();
67 var rounds = kdfOptsBuf.readInt();
68 var cinf = utils.opensshCipherInfo(cipher);
69 if (bcrypt === undefined) {
70 bcrypt = require('bcrypt-pbkdf');
71 }
72
73 if (typeof (options.passphrase) === 'string') {
74 options.passphrase = Buffer.from(options.passphrase,
75 'utf-8');
76 }
77 if (!Buffer.isBuffer(options.passphrase)) {
78 throw (new errors.KeyEncryptedError(
79 options.filename, 'OpenSSH'));
80 }
81
82 var pass = new Uint8Array(options.passphrase);
83 var salti = new Uint8Array(salt);
84 /* Use the pbkdf to derive both the key and the IV. */
85 var out = new Uint8Array(cinf.keySize + cinf.blockSize);
86 var res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,
87 out, out.length, rounds);
88 if (res !== 0) {
89 throw (new Error('bcrypt_pbkdf function returned ' +
90 'failure, parameters invalid'));
91 }
92 out = Buffer.from(out);
93 var ckey = out.slice(0, cinf.keySize);
94 var iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);
95 var cipherStream = crypto.createDecipheriv(cinf.opensslName,
96 ckey, iv);
97 cipherStream.setAutoPadding(false);
98 var chunk, chunks = [];
99 cipherStream.once('error', function (e) {
100 if (e.toString().indexOf('bad decrypt') !== -1) {
101 throw (new Error('Incorrect passphrase ' +
102 'supplied, could not decrypt key'));
103 }
104 throw (e);
105 });
106 cipherStream.write(privKeyBlob);
107 cipherStream.end();
108 while ((chunk = cipherStream.read()) !== null)
109 chunks.push(chunk);
110 privKeyBlob = Buffer.concat(chunks);
111 break;
112 default:
113 throw (new Error(
114 'OpenSSH-format key uses unknown KDF "' + kdf + '"'));
115 }
116
117 buf = new SSHBuffer({buffer: privKeyBlob});
118
119 var checkInt1 = buf.readInt();
120 var checkInt2 = buf.readInt();
121 if (checkInt1 !== checkInt2) {
122 throw (new Error('Incorrect passphrase supplied, could not ' +
123 'decrypt key'));
124 }
125
126 var ret = {};
127 var key = rfc4253.readInternal(ret, 'private', buf.remainder());
128
129 buf.skip(ret.consumed);
130
131 var comment = buf.readString();
132 key.comment = comment;
133
134 return (key);
135}
136
137function write(key, options) {
138 var pubKey;
139 if (PrivateKey.isPrivateKey(key))
140 pubKey = key.toPublic();
141 else
142 pubKey = key;
143
144 var cipher = 'none';
145 var kdf = 'none';
146 var kdfopts = Buffer.alloc(0);
147 var cinf = { blockSize: 8 };
148 var passphrase;
149 if (options !== undefined) {
150 passphrase = options.passphrase;
151 if (typeof (passphrase) === 'string')
152 passphrase = Buffer.from(passphrase, 'utf-8');
153 if (passphrase !== undefined) {
154 assert.buffer(passphrase, 'options.passphrase');
155 assert.optionalString(options.cipher, 'options.cipher');
156 cipher = options.cipher;
157 if (cipher === undefined)
158 cipher = 'aes128-ctr';
159 cinf = utils.opensshCipherInfo(cipher);
160 kdf = 'bcrypt';
161 }
162 }
163
164 var privBuf;
165 if (PrivateKey.isPrivateKey(key)) {
166 privBuf = new SSHBuffer({});
167 var checkInt = crypto.randomBytes(4).readUInt32BE(0);
168 privBuf.writeInt(checkInt);
169 privBuf.writeInt(checkInt);
170 privBuf.write(key.toBuffer('rfc4253'));
171 privBuf.writeString(key.comment || '');
172
173 var n = 1;
174 while (privBuf._offset % cinf.blockSize !== 0)
175 privBuf.writeChar(n++);
176 privBuf = privBuf.toBuffer();
177 }
178
179 switch (kdf) {
180 case 'none':
181 break;
182 case 'bcrypt':
183 var salt = crypto.randomBytes(16);
184 var rounds = 16;
185 var kdfssh = new SSHBuffer({});
186 kdfssh.writeBuffer(salt);
187 kdfssh.writeInt(rounds);
188 kdfopts = kdfssh.toBuffer();
189
190 if (bcrypt === undefined) {
191 bcrypt = require('bcrypt-pbkdf');
192 }
193 var pass = new Uint8Array(passphrase);
194 var salti = new Uint8Array(salt);
195 /* Use the pbkdf to derive both the key and the IV. */
196 var out = new Uint8Array(cinf.keySize + cinf.blockSize);
197 var res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,
198 out, out.length, rounds);
199 if (res !== 0) {
200 throw (new Error('bcrypt_pbkdf function returned ' +
201 'failure, parameters invalid'));
202 }
203 out = Buffer.from(out);
204 var ckey = out.slice(0, cinf.keySize);
205 var iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);
206
207 var cipherStream = crypto.createCipheriv(cinf.opensslName,
208 ckey, iv);
209 cipherStream.setAutoPadding(false);
210 var chunk, chunks = [];
211 cipherStream.once('error', function (e) {
212 throw (e);
213 });
214 cipherStream.write(privBuf);
215 cipherStream.end();
216 while ((chunk = cipherStream.read()) !== null)
217 chunks.push(chunk);
218 privBuf = Buffer.concat(chunks);
219 break;
220 default:
221 throw (new Error('Unsupported kdf ' + kdf));
222 }
223
224 var buf = new SSHBuffer({});
225
226 buf.writeCString(MAGIC);
227 buf.writeString(cipher); /* cipher */
228 buf.writeString(kdf); /* kdf */
229 buf.writeBuffer(kdfopts); /* kdfoptions */
230
231 buf.writeInt(1); /* nkeys */
232 buf.writeBuffer(pubKey.toBuffer('rfc4253'));
233
234 if (privBuf)
235 buf.writeBuffer(privBuf);
236
237 buf = buf.toBuffer();
238
239 var header;
240 if (PrivateKey.isPrivateKey(key))
241 header = 'OPENSSH PRIVATE KEY';
242 else
243 header = 'OPENSSH PUBLIC KEY';
244
245 var tmp = buf.toString('base64');
246 var len = tmp.length + (tmp.length / 70) +
247 18 + 16 + header.length*2 + 10;
248 buf = Buffer.alloc(len);
249 var o = 0;
250 o += buf.write('-----BEGIN ' + header + '-----\n', o);
251 for (var i = 0; i < tmp.length; ) {
252 var limit = i + 70;
253 if (limit > tmp.length)
254 limit = tmp.length;
255 o += buf.write(tmp.slice(i, limit), o);
256 buf[o++] = 10;
257 i = limit;
258 }
259 o += buf.write('-----END ' + header + '-----\n', o);
260
261 return (buf.slice(0, o));
262}
Note: See TracBrowser for help on using the repository browser.