/* 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));