putty.js (2335B)
1 // Copyright 2018 Joyent, Inc. 2 3 module.exports = { 4 read: read, 5 write: write 6 }; 7 8 var assert = require('assert-plus'); 9 var Buffer = require('safer-buffer').Buffer; 10 var rfc4253 = require('./rfc4253'); 11 var Key = require('../key'); 12 13 var errors = require('../errors'); 14 15 function read(buf, options) { 16 var lines = buf.toString('ascii').split(/[\r\n]+/); 17 var found = false; 18 var parts; 19 var si = 0; 20 while (si < lines.length) { 21 parts = splitHeader(lines[si++]); 22 if (parts && 23 parts[0].toLowerCase() === 'putty-user-key-file-2') { 24 found = true; 25 break; 26 } 27 } 28 if (!found) { 29 throw (new Error('No PuTTY format first line found')); 30 } 31 var alg = parts[1]; 32 33 parts = splitHeader(lines[si++]); 34 assert.equal(parts[0].toLowerCase(), 'encryption'); 35 36 parts = splitHeader(lines[si++]); 37 assert.equal(parts[0].toLowerCase(), 'comment'); 38 var comment = parts[1]; 39 40 parts = splitHeader(lines[si++]); 41 assert.equal(parts[0].toLowerCase(), 'public-lines'); 42 var publicLines = parseInt(parts[1], 10); 43 if (!isFinite(publicLines) || publicLines < 0 || 44 publicLines > lines.length) { 45 throw (new Error('Invalid public-lines count')); 46 } 47 48 var publicBuf = Buffer.from( 49 lines.slice(si, si + publicLines).join(''), 'base64'); 50 var keyType = rfc4253.algToKeyType(alg); 51 var key = rfc4253.read(publicBuf); 52 if (key.type !== keyType) { 53 throw (new Error('Outer key algorithm mismatch')); 54 } 55 key.comment = comment; 56 return (key); 57 } 58 59 function splitHeader(line) { 60 var idx = line.indexOf(':'); 61 if (idx === -1) 62 return (null); 63 var header = line.slice(0, idx); 64 ++idx; 65 while (line[idx] === ' ') 66 ++idx; 67 var rest = line.slice(idx); 68 return ([header, rest]); 69 } 70 71 function write(key, options) { 72 assert.object(key); 73 if (!Key.isKey(key)) 74 throw (new Error('Must be a public key')); 75 76 var alg = rfc4253.keyTypeToAlg(key); 77 var buf = rfc4253.write(key); 78 var comment = key.comment || ''; 79 80 var b64 = buf.toString('base64'); 81 var lines = wrap(b64, 64); 82 83 lines.unshift('Public-Lines: ' + lines.length); 84 lines.unshift('Comment: ' + comment); 85 lines.unshift('Encryption: none'); 86 lines.unshift('PuTTY-User-Key-File-2: ' + alg); 87 88 return (Buffer.from(lines.join('\n') + '\n')); 89 } 90 91 function wrap(txt, len) { 92 var lines = []; 93 var pos = 0; 94 while (pos < txt.length) { 95 lines.push(txt.slice(pos, pos + 64)); 96 pos += 64; 97 } 98 return (lines); 99 }