jwk-to-ssh.js/lib/ssh-packer.js

77 lines
1.7 KiB
JavaScript

'use strict';
var Enc = require('./encoding.js');
var SSH = module.exports;
SSH.pack = function (opts) {
var jwk = opts.jwk;
var els = [];
var ssh = {
type: ''
, _elements: els
, comment: opts.comment || ''
};
var len;
if ("RSA" === jwk.kty) {
ssh.type = 'ssh-rsa';
els.push(Enc.binToHex(ssh.type));
els.push(SSH._padRsa(Enc.base64ToHex(jwk.e)));
els.push(SSH._padRsa(Enc.base64ToHex(jwk.n)));
return SSH._packElements(ssh);
}
if ("P-256" === jwk.crv) {
ssh.type = 'ecdsa-sha2-nistp256';
els.push(Enc.binToHex(ssh.type));
els.push(Enc.binToHex('nistp256'));
len = 32;
} else if ("P-384" === jwk.crv) {
ssh.type = 'ecdsa-sha2-nistp384';
els.push(Enc.binToHex(ssh.type));
els.push(Enc.binToHex('nistp384'));
len = 48;
} else {
throw new Error("unknown key type " + (jwk.crv || jwk.kty));
}
els.push('04'
+ SSH._padEc(Enc.base64ToHex(jwk.x), len)
+ SSH._padEc(Enc.base64ToHex(jwk.y), len)
);
return SSH._packElements(ssh);
};
SSH._packElements = function (ssh) {
var hex = ssh._elements.map(function (hex) {
return SSH._numToUint32Hex(hex.length/2) + hex;
}).join('');
return [ ssh.type, Enc.hexToBase64(hex), ssh.comment ].join(' ');
};
SSH._numToUint32Hex = function (num) {
var hex = num.toString(16);
while (hex.length < 8) {
hex = '0' + hex;
}
return hex;
};
SSH._padRsa = function (hex) {
// BigInt is negative if the high order bit 0x80 is set,
// so ASN1, SSH, and many other formats pad with '0x00'
// to signifiy a positive number.
var i = parseInt(hex.slice(0, 2), 16);
if (0x80 & i) {
return '00' + hex;
}
return hex;
};
SSH._padEc = function (hex, len) {
while (hex.length < len * 2) {
hex = '00' + hex;
}
return hex;
};