bluecrypt-jwk-to-ssh.js/jwk-to-ssh.js

121 lines
2.9 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
;(function (exports) {
'use strict';
if (!exports.Enc) { exports.Enc = {}; }
if (!exports.SSH) { exports.SSH = {}; }
var Enc = exports.Enc;
var SSH = exports.SSH;
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) {
console.log(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;
}
console.log('length', 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;
};
Enc.base64ToHex = function (b64) {
var bin = atob(Enc.urlBase64ToBase64(b64));
return Enc.binToHex(bin);
};
Enc.binToHex = function (bin) {
return bin.split('').map(function (ch) {
var h = ch.charCodeAt(0).toString(16);
if (h.length % 2) { h = '0' + h; }
return h;
}).join('');
};
Enc.hexToBase64 = function (hex) {
return btoa(Enc.hexToBin(hex));
};
Enc.hexToBin = function (hex) {
return hex.match(/.{2}/g).map(function (h) {
return String.fromCharCode(parseInt(h, 16));
}).join('');
};
Enc.urlBase64ToBase64 = function urlsafeBase64ToBase64(str) {
var r = str % 4;
if (2 === r) {
str += '==';
} else if (3 === r) {
str += '=';
}
return str.replace(/-/g, '+').replace(/_/g, '/');
};
}('undefined' !== typeof window ? window : module.exports));