diff --git a/base64url.js b/base64url.js index fb2a67c..8a35147 100644 --- a/base64url.js +++ b/base64url.js @@ -1,21 +1,28 @@ +/*jslint browser: true, sloppy: true */ //adapted from https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-08#appendix-C -function base64urlEncode(s) { +function base64urlEncode(arg) { var s = window.btoa(arg); // Regular base64 encoder s = s.split('=')[0]; // Remove any trailing '='s - s = s.replace(/+/g, '-'); // 62nd char of encoding + s = s.replace(/\+/g, '-'); // 62nd char of encoding s = s.replace(/\//g, '_'); // 63rd char of encoding return s; } -function base64urlDecode(s) { +function base64urlDecode(s) { s = s.replace(/-/g, '+'); // 62nd char of encoding s = s.replace(/_/g, '/'); // 63rd char of encoding switch (s.length % 4) { // Pad with trailing '='s - case 0: break; // No pad chars in this case - case 2: s += "=="; break; // Two pad chars - case 3: s += "="; break; // One pad char - default: throw "Illegal base64url string!"; + case 0: // No pad chars in this case + break; + case 2: // Two pad chars + s += "=="; + break; + case 3: // One pad char + s += "="; + break; + default: + throw "Illegal base64url string!"; } return window.atob(s); // Standard base64 decoder -} \ No newline at end of file +} diff --git a/js-keygen-ui.js b/js-keygen-ui.js index 9c651da..3e2a894 100644 --- a/js-keygen-ui.js +++ b/js-keygen-ui.js @@ -1,5 +1,8 @@ +/*jslint browser: true, sloppy: true, vars: true, indent: 2*/ +var console, generateKeyPair; + function copy(id) { - return function() { + return function () { var ta = document.querySelector(id); ta.focus(); ta.select(); @@ -7,43 +10,43 @@ function copy(id) { var successful = document.execCommand('copy'); var msg = successful ? 'successful' : 'unsuccessful'; console.log('Copy key command was ' + msg); - } catch(err) { + } catch (err) { console.log('Oops, unable to copy'); } window.getSelection().removeAllRanges(); ta.blur(); - } + }; } function buildHref(data) { return "data:application/octet-stream;charset=utf-8;base64," + window.btoa(data); } -document.addEventListener("DOMContentLoaded", function(event) { - document.querySelector('#savePrivate').addEventListener('click', function(event) { +document.addEventListener("DOMContentLoaded", function (event) { + document.querySelector('#savePrivate').addEventListener('click', function (event) { document.querySelector('a#private').click(); }); document.querySelector('#copyPrivate').addEventListener('click', copy('#privateKey')); - document.querySelector('#savePublic').addEventListener('click', function(event) { + document.querySelector('#savePublic').addEventListener('click', function (event) { document.querySelector('a#public').click(); }); document.querySelector('#copyPublic').addEventListener('click', copy('#publicKey')); - document.querySelector('#generate').addEventListener('click', function(event) { + document.querySelector('#generate').addEventListener('click', function (event) { var name = document.querySelector('#name').value || "name"; document.querySelector('a#private').setAttribute("download", name + "_rsa"); document.querySelector('a#public').setAttribute("download", name + "_rsa.pub"); var alg = document.querySelector('#alg').value || "RSASSA-PKCS1-v1_5"; - var size = parseInt(document.querySelector('#size').value || "2048"); + var size = parseInt(document.querySelector('#size').value || "2048", 10); generateKeyPair(alg, size, name).then(function (keys) { document.querySelector('#private').setAttribute("href", buildHref(keys[0])); document.querySelector('#public').setAttribute("href", buildHref(keys[1])); document.querySelector('#privateKey').textContent = keys[0]; document.querySelector('#publicKey').textContent = keys[1]; document.querySelector('#result').style.display = "block"; - }).catch(function(err){ + }).catch(function (err) { console.error(err); }); }); -}); \ No newline at end of file +}); diff --git a/js-keygen.js b/js-keygen.js index 98c9a48..17e442b 100644 --- a/js-keygen.js +++ b/js-keygen.js @@ -1,8 +1,11 @@ +/*jslint browser: true, devel: true, sloppy: true, vars: true*/ +/*globals Uint8Array, Promise */ var extractable = true; +var encodePrivateKey, encodePublicKey; function wrap(text, len) { var length = len || 72, i, result = ""; - for(i=0; i < text.length; i += length) { + for (i = 0; i < text.length; i += length) { result += text.slice(i, i + length) + "\n"; } return result; @@ -12,39 +15,39 @@ function rsaPrivateKey(key) { return "-----BEGIN RSA PRIVATE KEY-----\n" + key + "-----END RSA PRIVATE KEY-----"; } -function arrayBufferToBase64( buffer ) { - var binary = ''; - var bytes = new Uint8Array( buffer ); - var len = bytes.byteLength; - for (var i = 0; i < len; i++) { - binary += String.fromCharCode( bytes[ i ] ); - } - return window.btoa( binary ); +function arrayBufferToBase64(buffer) { + var binary = '', i; + var bytes = new Uint8Array(buffer); + var len = bytes.byteLength; + for (i = 0; i < len; i += 1) { + binary += String.fromCharCode(bytes[i]); + } + return window.btoa(binary); } function generateKeyPair(alg, size, name) { - return window.crypto.subtle.generateKey({ - name: "RSASSA-PKCS1-v1_5", - modulusLength: 2048, //can be 1024, 2048, or 4096 - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" - }, - extractable, - ["sign", "verify"] - ).then(function(key){ + return window.crypto.subtle.generateKey({ + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, //can be 1024, 2048, or 4096 + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: {name: "SHA-1"} //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" + }, + extractable, + ["sign", "verify"] + ).then(function (key) { - var private = window.crypto.subtle.exportKey( + var privateKey = window.crypto.subtle.exportKey( "jwk", key.privateKey - ).then(encodePrivateKey).then(wrap).then(rsaPrivateKey); + ).then(encodePrivateKey).then(wrap).then(rsaPrivateKey); - var public = window.crypto.subtle.exportKey( + var publicKey = window.crypto.subtle.exportKey( "jwk", key.publicKey - ).then(function(jwk){ + ).then(function (jwk) { return encodePublicKey(jwk, name); - }); + }); - return Promise.all([private, public]); + return Promise.all([privateKey, publicKey]); }); -} \ No newline at end of file +} diff --git a/ssh-util.js b/ssh-util.js index 7e9b5f3..bf261cb 100644 --- a/ssh-util.js +++ b/ssh-util.js @@ -1,3 +1,7 @@ +/*jslint browser: true, devel: true, bitwise: true, sloppy: true, vars: true*/ + +var base64urlDecode; + function arrayToString(a) { return String.fromCharCode.apply(null, a); } @@ -17,14 +21,14 @@ function pemToArray(pem) { } function arrayToPem(a) { - return window.btoa(a.map(function (c) { + return window.btoa(a.map(function (c) { return String.fromCharCode(c); }).join('')); } function arrayToLen(a) { var result = 0, i; - for(i = 0; i < a.length; i++) { + for (i = 0; i < a.length; i += 1) { result = result * 256 + a[i]; } return result; @@ -32,7 +36,7 @@ function arrayToLen(a) { function integerToOctet(n) { var result = []; - for(;n > 0; n = n >> 8 ) { + for (true; n > 0; n = n >> 8) { result.push(n & 0xFF); } return result.reverse(); @@ -40,7 +44,7 @@ function integerToOctet(n) { function lenToArray(n) { var oct = integerToOctet(n), i; - for(i = oct.length; i < 4; i++) { + for (i = oct.length; i < 4; i += 1) { oct.unshift(0); } return oct; @@ -49,13 +53,13 @@ function lenToArray(n) { function decodePublicKey(s) { var split = s.split(" "); var prefix = split[0]; - if(prefix != "ssh-rsa") { + if (prefix !== "ssh-rsa") { throw ("Unknown prefix:" + prefix); } var buffer = pemToArray(split[1]); var nameLen = arrayToLen(buffer.splice(0, 4)); var type = arrayToString(buffer.splice(0, nameLen)); - if(type != "ssh-rsa") { + if (type !== "ssh-rsa") { throw ("Unknown key type:" + type); } var exponentLen = arrayToLen(buffer.splice(0, 4)); @@ -65,22 +69,22 @@ function decodePublicKey(s) { return {type: type, exponent: exponent, key: key, name: split[2]}; } +function checkHighestBit(v) { + if (v[0] >> 7 === 1) { // add leading zero if first bit is set + v.unshift(0); + } + return v; +} + function jwkToInternal(jwk) { return { type: "ssh-rsa", exponent: checkHighestBit(stringToArray(base64urlDecode(jwk.e))), - name: "name", + name: "name", key: checkHighestBit(stringToArray(base64urlDecode(jwk.n))) }; } -function checkHighestBit(v) { - if(v[0] >> 7 === 1) { // add leading zero if first bit is set - v.unshift(0); - } - return v; -} - function encodePublicKey(jwk, name) { var k = jwkToInternal(jwk); k.name = name; @@ -94,7 +98,7 @@ function encodePublicKey(jwk, name) { function asnEncodeLen(n) { var result = []; - if(n >> 7) { + if (n >> 7) { result = integerToOctet(n); result.unshift(0x80 + result.length); } else { @@ -113,6 +117,6 @@ function encodePrivateKey(jwk) { var seq = [0x02, 0x01, 0x00]; // extra seq for SSH seq = seq.concat.apply(seq, list); var len = asnEncodeLen(seq.length); - var a = [0x30].concat(len , seq); // seq is 0x30 + var a = [0x30].concat(len, seq); // seq is 0x30 return arrayToPem(a); -} \ No newline at end of file +}