Skip to content

Commit c0db00d

Browse files
committed
Exporting OpenSSH private key
1 parent ea68a7f commit c0db00d

File tree

1 file changed

+95
-2
lines changed

1 file changed

+95
-2
lines changed

src/formats/openssh.js

+95-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,95 @@ const PRIVATE_CLOSING_BOUNDARY = '-----END OPENSSH PRIVATE KEY-----';
77

88
module.exports = {
99
privateExport: function (key, options) {
10-
throw Error('Not implemented yet.');
10+
const nbuf = key.n.toBuffer();
11+
12+
let ebuf = Buffer.alloc(4)
13+
ebuf.writeUInt32BE(key.e, 0);
14+
//Slice leading zeroes
15+
while(ebuf[0] === 0) ebuf = ebuf.slice(1);
16+
17+
const dbuf = key.d.toBuffer();
18+
const coeffbuf = key.coeff.toBuffer();
19+
const pbuf = key.p.toBuffer();
20+
const qbuf = key.q.toBuffer();
21+
let commentbuf;
22+
if(typeof key.sshcomment !== 'undefined'){
23+
commentbuf = Buffer.from(key.sshcomment);
24+
} else {
25+
commentbuf = Buffer.from([]);
26+
}
27+
28+
const pubkeyLength =
29+
11 + // 32bit length, 'ssh-rsa'
30+
4 + ebuf.byteLength +
31+
4 + nbuf.byteLength;
32+
33+
const privateKeyLength =
34+
8 + //64bit unused checksum
35+
11 + // 32bit length, 'ssh-rsa'
36+
4 + nbuf.byteLength +
37+
4 + ebuf.byteLength +
38+
4 + dbuf.byteLength +
39+
4 + coeffbuf.byteLength +
40+
4 + pbuf.byteLength +
41+
4 + qbuf.byteLength +
42+
4 + commentbuf.byteLength;
43+
44+
let length =
45+
15 + //openssh-key-v1,0x00,
46+
16 + // 2*(32bit length, 'none')
47+
4 + // 32bit length, empty string
48+
4 + // 32bit number of keys
49+
4 + // 32bit pubkey length
50+
pubkeyLength +
51+
4 + //32bit private+checksum+comment+padding length
52+
privateKeyLength;
53+
54+
const paddingLength = Math.ceil(privateKeyLength / 8)*8 - privateKeyLength;
55+
length += paddingLength;
56+
57+
const buf = Buffer.alloc(length);
58+
const writer = {buf:buf, off: 0};
59+
buf.write('openssh-key-v1', 'utf8');
60+
buf.writeUInt8(0, 14);
61+
writer.off += 15;
62+
63+
writeOpenSSHKeyString(writer, Buffer.from('none'));
64+
writeOpenSSHKeyString(writer, Buffer.from('none'));
65+
writeOpenSSHKeyString(writer, Buffer.from(''));
66+
67+
writer.off = writer.buf.writeUInt32BE(1, writer.off);
68+
writer.off = writer.buf.writeUInt32BE(pubkeyLength, writer.off);
69+
70+
writeOpenSSHKeyString(writer, Buffer.from('ssh-rsa'));
71+
writeOpenSSHKeyString(writer, ebuf);
72+
writeOpenSSHKeyString(writer, nbuf);
73+
74+
writer.off = writer.buf.writeUInt32BE(
75+
length - 47 - pubkeyLength,
76+
writer.off
77+
);
78+
writer.off += 8;
79+
80+
writeOpenSSHKeyString(writer, Buffer.from('ssh-rsa'));
81+
writeOpenSSHKeyString(writer, nbuf);
82+
writeOpenSSHKeyString(writer, ebuf);
83+
writeOpenSSHKeyString(writer, dbuf);
84+
writeOpenSSHKeyString(writer, coeffbuf);
85+
writeOpenSSHKeyString(writer, pbuf);
86+
writeOpenSSHKeyString(writer, qbuf);
87+
writeOpenSSHKeyString(writer, commentbuf);
88+
89+
let pad = 0x01;
90+
while(writer.off < length){
91+
writer.off = writer.buf.writeUInt8(pad++, writer.off);
92+
}
93+
94+
if(options.type === 'der'){
95+
return writer.buf
96+
} else {
97+
return PRIVATE_OPENING_BOUNDARY + '\n' + utils.linebrk(buf.toString('base64'), 70) + '\n' + PRIVATE_CLOSING_BOUNDARY;
98+
}
1199
},
12100

13101
privateImport: function (key, data, options) {
@@ -110,7 +198,12 @@ module.exports = {
110198
writeOpenSSHKeyString(writer, nbuf);
111199

112200
let comment = key.sshcomment || '';
113-
return 'ssh-rsa ' + buf.toString('base64') + ' ' + comment;
201+
202+
if(options.type === 'der'){
203+
return writer.buf
204+
} else {
205+
return 'ssh-rsa ' + buf.toString('base64') + ' ' + comment;
206+
}
114207
},
115208

116209
publicImport: function (key, data, options) {

0 commit comments

Comments
 (0)