Prettier all the things
This commit is contained in:
parent
e4a0c7f193
commit
355e22bcd6
10 changed files with 518 additions and 192 deletions
|
@ -1,5 +1,4 @@
|
||||||
Generate a ssh keypair using the webcrypto API
|
# Generate a ssh keypair using the webcrypto API
|
||||||
==
|
|
||||||
|
|
||||||
See the live demo at https://js-keygen.surge.sh
|
See the live demo at https://js-keygen.surge.sh
|
||||||
|
|
||||||
|
@ -11,8 +10,6 @@ There is no way to generate a ssh keypair on the chrome book, but we have access
|
||||||
* I had to learn about ASN.1 to encode the private key for OpenSSH
|
* I had to learn about ASN.1 to encode the private key for OpenSSH
|
||||||
* I had to lean about the open SSH public format to encode the public key for OpenSSH
|
* I had to lean about the open SSH public format to encode the public key for OpenSSH
|
||||||
|
|
||||||
|
|
||||||
The end result is a usable single page app that will locally generate a keypair you can save to local drive. Allowing you to do that straight from chrome on a chrome book.
|
The end result is a usable single page app that will locally generate a keypair you can save to local drive. Allowing you to do that straight from chrome on a chrome book.
|
||||||
|
|
||||||
Everywhere else, you should have access to ssh-keygen which is the recommended way to generate keypair for SSH.
|
Everywhere else, you should have access to ssh-keygen which is the recommended way to generate keypair for SSH.
|
||||||
|
|
||||||
|
|
10
base64url.js
10
base64url.js
|
@ -3,15 +3,15 @@
|
||||||
|
|
||||||
function base64urlEncode(arg) {
|
function base64urlEncode(arg) {
|
||||||
var s = window.btoa(arg); // Regular base64 encoder
|
var s = window.btoa(arg); // Regular base64 encoder
|
||||||
s = s.split('=')[0]; // Remove any trailing '='s
|
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
|
s = s.replace(/\//g, "_"); // 63rd char of encoding
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64urlDecode(s) {
|
function base64urlDecode(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
|
s = s.replace(/_/g, "/"); // 63rd char of encoding
|
||||||
switch (s.length % 4) { // Pad with trailing '='s
|
switch (s.length % 4) { // Pad with trailing '='s
|
||||||
case 0: // No pad chars in this case
|
case 0: // No pad chars in this case
|
||||||
break;
|
break;
|
||||||
|
|
63
index.html
63
index.html
|
@ -1,5 +1,6 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>js-keygen</title>
|
<title>js-keygen</title>
|
||||||
<script src="base64url.js"></script>
|
<script src="base64url.js"></script>
|
||||||
|
@ -9,51 +10,77 @@
|
||||||
<link rel="stylesheet" href="js-keygen.css">
|
<link rel="stylesheet" href="js-keygen.css">
|
||||||
<link rel="icon" type="image/png" href="key.png">
|
<link rel="icon" type="image/png" href="key.png">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<h1>js-keygen</h1>
|
<h1>js-keygen</h1>
|
||||||
|
|
||||||
Generate a keypair to be used with openSSH, this replicate ssh-keygen function in javascript in the browser, using the webcrypto api and a bit of glue.<br>
|
Generate a keypair to be used with openSSH, this replicate ssh-keygen function in javascript in the browser, using the webcrypto
|
||||||
For an in-depth explanation on how this work, see the <a href="http://blog.roumanoff.com/2015/09/using-webcrypto-api-to-generate-keypair.html">blog post</a>.<br>
|
api and a bit of glue.
|
||||||
Usually you would want to save the private key to the machine initiating the ssh connection, and you want to copy the public key to the system receiving the connection.<br>
|
<br> For an in-depth explanation on how this work, see the
|
||||||
No data is being sent to the server, everything happens within the context of this web page.<br>
|
<a href="http://blog.roumanoff.com/2015/09/using-webcrypto-api-to-generate-keypair.html">blog post</a>.
|
||||||
|
<br> Usually you would want to save the private key to the machine initiating the ssh connection, and you want to copy the
|
||||||
|
public key to the system receiving the connection.
|
||||||
|
<br> No data is being sent to the server, everything happens within the context of this web page.
|
||||||
|
<br>
|
||||||
<a href="https://twitter.com/share" class="twitter-share-button" data-via="pkr2">Tweet</a>
|
<a href="https://twitter.com/share" class="twitter-share-button" data-via="pkr2">Tweet</a>
|
||||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script><hr>
|
<script>!function (d, s, id) { var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https'; if (!d.getElementById(id)) { js = d.createElement(s); js.id = id; js.src = p + '://platform.twitter.com/widgets.js'; fjs.parentNode.insertBefore(js, fjs); } }(document, 'script', 'twitter-wjs');</script>
|
||||||
<div><label for="name">Name:</label><input id="name" type="text" value="webcrypto"></div>
|
<hr>
|
||||||
<div><label for="alg">Algorithm:</label><select id="alg" disabled>
|
<div>
|
||||||
|
<label for="name">Name:</label>
|
||||||
|
<input id="name" type="text" value="webcrypto">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="alg">Algorithm:</label>
|
||||||
|
<select id="alg" disabled>
|
||||||
<option value="RSASSA-PKCS1-v1_5" selected>RSASSA-PKCS1-v1_5</option>
|
<option value="RSASSA-PKCS1-v1_5" selected>RSASSA-PKCS1-v1_5</option>
|
||||||
<option value="RSA-PSS">RSA-PSS</option>
|
<option value="RSA-PSS">RSA-PSS</option>
|
||||||
<option value="ECDSA">ECDSA</option>
|
<option value="ECDSA">ECDSA</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="size">Size:</label><select id="size" disabled>
|
<label for="size">Size:</label>
|
||||||
|
<select id="size" disabled>
|
||||||
<option value="1024" selected>1024</option>
|
<option value="1024" selected>1024</option>
|
||||||
<option value="2048">2048</option>
|
<option value="2048">2048</option>
|
||||||
<option value="4096">4096</option>
|
<option value="4096">4096</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div><label for="hash">Hash:</label><select id="hash" disabled>
|
<div>
|
||||||
|
<label for="hash">Hash:</label>
|
||||||
|
<select id="hash" disabled>
|
||||||
<option value="SHA-1" selected>SHA-1</option>
|
<option value="SHA-1" selected>SHA-1</option>
|
||||||
<option value="SHA-256">SHA-256</option>
|
<option value="SHA-256">SHA-256</option>
|
||||||
<option value="SHA-384">SHA-384</option>
|
<option value="SHA-384">SHA-384</option>
|
||||||
<option value="SHA-512">SHA-512</option>
|
<option value="SHA-512">SHA-512</option>
|
||||||
</select></div>
|
</select>
|
||||||
<label for="generate"></label><button id="generate">Generate</button>
|
</div>
|
||||||
|
<label for="generate"></label>
|
||||||
|
<button id="generate">Generate</button>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div id="result" style="display:none;">
|
<div id="result" style="display:none;">
|
||||||
<hr>
|
<hr>
|
||||||
<a id="private" style="display: none;" href="" download="id_rsa">id_rsa</a>
|
<a id="private" style="display: none;" href="" download="id_rsa">id_rsa</a>
|
||||||
<a id="public" style="display: none;" href="" download="id_rsa.pub">id_rsa.pub</a>
|
<a id="public" style="display: none;" href="" download="id_rsa.pub">id_rsa.pub</a>
|
||||||
Private Key <button id="copyPrivate">Copy</button> or <button id="savePrivate">Save</button><br>
|
Private Key
|
||||||
|
<button id="copyPrivate">Copy</button> or
|
||||||
|
<button id="savePrivate">Save</button>
|
||||||
|
<br>
|
||||||
<textarea id="privateKey" style="height: 150px;" spellcheck="false"></textarea>
|
<textarea id="privateKey" style="height: 150px;" spellcheck="false"></textarea>
|
||||||
|
|
||||||
<hr>
|
<hr> Public Key
|
||||||
Public Key <button id="copyPublic">Copy</button> or <button id="savePublic">Save</button><br>
|
<button id="copyPublic">Copy</button> or
|
||||||
|
<button id="savePublic">Save</button>
|
||||||
|
<br>
|
||||||
<textarea id="publicKey" spellcheck="false"></textarea>
|
<textarea id="publicKey" spellcheck="false"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr> Made with
|
||||||
Made with <span style="color:magenta;">♥</span> by <a href="http://blog.roumanoff.com">Patrick Roumanoff</a>
|
<span style="color:magenta;">♥</span> by
|
||||||
<a href="https://github.com/PatrickRoumanoff/js-keygen"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"></a>
|
<a href="http://blog.roumanoff.com">Patrick Roumanoff</a>
|
||||||
</div>
|
<a href="https://github.com/PatrickRoumanoff/js-keygen">
|
||||||
|
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67"
|
||||||
|
alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -2,16 +2,16 @@
|
||||||
var console, generateKeyPair;
|
var console, generateKeyPair;
|
||||||
|
|
||||||
function copy(id) {
|
function copy(id) {
|
||||||
return function () {
|
return function() {
|
||||||
var ta = document.querySelector(id);
|
var ta = document.querySelector(id);
|
||||||
ta.focus();
|
ta.focus();
|
||||||
ta.select();
|
ta.select();
|
||||||
try {
|
try {
|
||||||
var successful = document.execCommand('copy');
|
var successful = document.execCommand("copy");
|
||||||
var msg = successful ? 'successful' : 'unsuccessful';
|
var msg = successful ? "successful" : "unsuccessful";
|
||||||
console.log('Copy key command was ' + msg);
|
console.log("Copy key command was " + msg);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Oops, unable to copy');
|
console.log("Oops, unable to copy");
|
||||||
}
|
}
|
||||||
window.getSelection().removeAllRanges();
|
window.getSelection().removeAllRanges();
|
||||||
ta.blur();
|
ta.blur();
|
||||||
|
@ -22,30 +22,32 @@ function buildHref(data) {
|
||||||
return "data:application/octet-stream;charset=utf-8;base64," + window.btoa(data);
|
return "data:application/octet-stream;charset=utf-8;base64," + window.btoa(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function (event) {
|
document.addEventListener("DOMContentLoaded", function(event) {
|
||||||
document.querySelector('#savePrivate').addEventListener('click', function (event) {
|
document.querySelector("#savePrivate").addEventListener("click", function(event) {
|
||||||
document.querySelector('a#private').click();
|
document.querySelector("a#private").click();
|
||||||
});
|
});
|
||||||
document.querySelector('#copyPrivate').addEventListener('click', copy('#privateKey'));
|
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("a#public").click();
|
||||||
});
|
});
|
||||||
document.querySelector('#copyPublic').addEventListener('click', copy('#publicKey'));
|
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";
|
var name = document.querySelector("#name").value || "name";
|
||||||
document.querySelector('a#private').setAttribute("download", name + "_rsa");
|
document.querySelector("a#private").setAttribute("download", name + "_rsa");
|
||||||
document.querySelector('a#public').setAttribute("download", name + "_rsa.pub");
|
document.querySelector("a#public").setAttribute("download", name + "_rsa.pub");
|
||||||
|
|
||||||
var alg = document.querySelector('#alg').value || "RSASSA-PKCS1-v1_5";
|
var alg = document.querySelector("#alg").value || "RSASSA-PKCS1-v1_5";
|
||||||
var size = parseInt(document.querySelector('#size').value || "2048", 10);
|
var size = parseInt(document.querySelector("#size").value || "2048", 10);
|
||||||
generateKeyPair(alg, size, name).then(function (keys) {
|
generateKeyPair(alg, size, name)
|
||||||
document.querySelector('#private').setAttribute("href", buildHref(keys[0]));
|
.then(function(keys) {
|
||||||
document.querySelector('#public').setAttribute("href", buildHref(keys[1]));
|
document.querySelector("#private").setAttribute("href", buildHref(keys[0]));
|
||||||
document.querySelector('#privateKey').textContent = keys[0];
|
document.querySelector("#public").setAttribute("href", buildHref(keys[1]));
|
||||||
document.querySelector('#publicKey').textContent = keys[1];
|
document.querySelector("#privateKey").textContent = keys[0];
|
||||||
document.querySelector('#result').style.display = "block";
|
document.querySelector("#publicKey").textContent = keys[1];
|
||||||
}).catch(function (err) {
|
document.querySelector("#result").style.display = "block";
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
button#generate {
|
button#generate {
|
||||||
background-color: rgb(60,200,30);
|
background-color: rgb(60, 200, 30);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -29,7 +29,7 @@ label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
select{
|
select {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
|
|
31
js-keygen.js
31
js-keygen.js
|
@ -4,7 +4,9 @@ var extractable = true;
|
||||||
var encodePrivateKey, encodePublicKey;
|
var encodePrivateKey, encodePublicKey;
|
||||||
|
|
||||||
function wrap(text, len) {
|
function wrap(text, len) {
|
||||||
var length = len || 72, i, result = "";
|
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";
|
result += text.slice(i, i + length) + "\n";
|
||||||
}
|
}
|
||||||
|
@ -16,7 +18,8 @@ function rsaPrivateKey(key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrayBufferToBase64(buffer) {
|
function arrayBufferToBase64(buffer) {
|
||||||
var binary = '', i;
|
var binary = "",
|
||||||
|
i;
|
||||||
var bytes = new Uint8Array(buffer);
|
var bytes = new Uint8Array(buffer);
|
||||||
var len = bytes.byteLength;
|
var len = bytes.byteLength;
|
||||||
for (i = 0; i < len; i += 1) {
|
for (i = 0; i < len; i += 1) {
|
||||||
|
@ -26,25 +29,25 @@ function arrayBufferToBase64(buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateKeyPair(alg, size, name) {
|
function generateKeyPair(alg, size, name) {
|
||||||
return window.crypto.subtle.generateKey({
|
return window.crypto.subtle
|
||||||
|
.generateKey(
|
||||||
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSASSA-PKCS1-v1_5",
|
||||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||||
hash: {name: "SHA-1"} //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
hash: { name: "SHA-1" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||||
},
|
},
|
||||||
extractable,
|
extractable,
|
||||||
["sign", "verify"]
|
["sign", "verify"]
|
||||||
).then(function (key) {
|
)
|
||||||
|
.then(function(key) {
|
||||||
|
var privateKey = window.crypto.subtle
|
||||||
|
.exportKey("jwk", key.privateKey)
|
||||||
|
.then(encodePrivateKey)
|
||||||
|
.then(wrap)
|
||||||
|
.then(rsaPrivateKey);
|
||||||
|
|
||||||
var privateKey = window.crypto.subtle.exportKey(
|
var publicKey = window.crypto.subtle.exportKey("jwk", key.publicKey).then(function(jwk) {
|
||||||
"jwk",
|
|
||||||
key.privateKey
|
|
||||||
).then(encodePrivateKey).then(wrap).then(rsaPrivateKey);
|
|
||||||
|
|
||||||
var publicKey = window.crypto.subtle.exportKey(
|
|
||||||
"jwk",
|
|
||||||
key.publicKey
|
|
||||||
).then(function (jwk) {
|
|
||||||
return encodePublicKey(jwk, name);
|
return encodePublicKey(jwk, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
"name": "js-keypair",
|
"name": "js-keypair",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Generate a key pair using the webcrypto API",
|
"description": "Generate a key pair using the webcrypto API",
|
||||||
"main": "keypair.js",
|
"main": "js-keygen.js",
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
},
|
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"To run test open test/index.html in your browser\""
|
||||||
},
|
},
|
||||||
"author": "patrick@roumanoff.com",
|
"author": "patrick@roumanoff.com",
|
||||||
"license": "Apache 2.0"
|
"license": "Apache 2.0"
|
||||||
|
|
31
ssh-util.js
31
ssh-util.js
|
@ -7,7 +7,7 @@ function arrayToString(a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringToArray(s) {
|
function stringToArray(s) {
|
||||||
return s.split('').map(function (c) {
|
return s.split("").map(function(c) {
|
||||||
return c.charCodeAt();
|
return c.charCodeAt();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,18 @@ function pemToArray(pem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrayToPem(a) {
|
function arrayToPem(a) {
|
||||||
return window.btoa(a.map(function (c) {
|
return window.btoa(
|
||||||
|
a
|
||||||
|
.map(function(c) {
|
||||||
return String.fromCharCode(c);
|
return String.fromCharCode(c);
|
||||||
}).join(''));
|
})
|
||||||
|
.join("")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrayToLen(a) {
|
function arrayToLen(a) {
|
||||||
var result = 0, i;
|
var result = 0,
|
||||||
|
i;
|
||||||
for (i = 0; i < a.length; i += 1) {
|
for (i = 0; i < a.length; i += 1) {
|
||||||
result = result * 256 + a[i];
|
result = result * 256 + a[i];
|
||||||
}
|
}
|
||||||
|
@ -37,13 +42,14 @@ function arrayToLen(a) {
|
||||||
function integerToOctet(n) {
|
function integerToOctet(n) {
|
||||||
var result = [];
|
var result = [];
|
||||||
for (true; n > 0; n = n >> 8) {
|
for (true; n > 0; n = n >> 8) {
|
||||||
result.push(n & 0xFF);
|
result.push(n & 0xff);
|
||||||
}
|
}
|
||||||
return result.reverse();
|
return result.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
function lenToArray(n) {
|
function lenToArray(n) {
|
||||||
var oct = integerToOctet(n), i;
|
var oct = integerToOctet(n),
|
||||||
|
i;
|
||||||
for (i = oct.length; i < 4; i += 1) {
|
for (i = oct.length; i < 4; i += 1) {
|
||||||
oct.unshift(0);
|
oct.unshift(0);
|
||||||
}
|
}
|
||||||
|
@ -54,23 +60,24 @@ function decodePublicKey(s) {
|
||||||
var split = s.split(" ");
|
var split = s.split(" ");
|
||||||
var prefix = split[0];
|
var prefix = split[0];
|
||||||
if (prefix !== "ssh-rsa") {
|
if (prefix !== "ssh-rsa") {
|
||||||
throw ("Unknown prefix:" + prefix);
|
throw "Unknown prefix:" + prefix;
|
||||||
}
|
}
|
||||||
var buffer = pemToArray(split[1]);
|
var buffer = pemToArray(split[1]);
|
||||||
var nameLen = arrayToLen(buffer.splice(0, 4));
|
var nameLen = arrayToLen(buffer.splice(0, 4));
|
||||||
var type = arrayToString(buffer.splice(0, nameLen));
|
var type = arrayToString(buffer.splice(0, nameLen));
|
||||||
if (type !== "ssh-rsa") {
|
if (type !== "ssh-rsa") {
|
||||||
throw ("Unknown key type:" + type);
|
throw "Unknown key type:" + type;
|
||||||
}
|
}
|
||||||
var exponentLen = arrayToLen(buffer.splice(0, 4));
|
var exponentLen = arrayToLen(buffer.splice(0, 4));
|
||||||
var exponent = buffer.splice(0, exponentLen);
|
var exponent = buffer.splice(0, exponentLen);
|
||||||
var keyLen = arrayToLen(buffer.splice(0, 4));
|
var keyLen = arrayToLen(buffer.splice(0, 4));
|
||||||
var key = buffer.splice(0, keyLen);
|
var key = buffer.splice(0, keyLen);
|
||||||
return {type: type, exponent: exponent, key: key, name: split[2]};
|
return { type: type, exponent: exponent, key: key, name: split[2] };
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkHighestBit(v) {
|
function checkHighestBit(v) {
|
||||||
if (v[0] >> 7 === 1) { // add leading zero if first bit is set
|
if (v[0] >> 7 === 1) {
|
||||||
|
// add leading zero if first bit is set
|
||||||
v.unshift(0);
|
v.unshift(0);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
@ -81,7 +88,7 @@ function jwkToInternal(jwk) {
|
||||||
type: "ssh-rsa",
|
type: "ssh-rsa",
|
||||||
exponent: checkHighestBit(stringToArray(base64urlDecode(jwk.e))),
|
exponent: checkHighestBit(stringToArray(base64urlDecode(jwk.e))),
|
||||||
name: "name",
|
name: "name",
|
||||||
key: checkHighestBit(stringToArray(base64urlDecode(jwk.n)))
|
key: checkHighestBit(stringToArray(base64urlDecode(jwk.n))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +116,7 @@ function asnEncodeLen(n) {
|
||||||
|
|
||||||
function encodePrivateKey(jwk) {
|
function encodePrivateKey(jwk) {
|
||||||
var order = ["n", "e", "d", "p", "q", "dp", "dq", "qi"];
|
var order = ["n", "e", "d", "p", "q", "dp", "dq", "qi"];
|
||||||
var list = order.map(function (prop) {
|
var list = order.map(function(prop) {
|
||||||
var v = checkHighestBit(stringToArray(base64urlDecode(jwk[prop])));
|
var v = checkHighestBit(stringToArray(base64urlDecode(jwk[prop])));
|
||||||
var len = asnEncodeLen(v.length);
|
var len = asnEncodeLen(v.length);
|
||||||
return [0x02].concat(len, v); // int tag is 0x02
|
return [0x02].concat(len, v); // int tag is 0x02
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>QUnit Example</title>
|
<title>QUnit Example</title>
|
||||||
<link rel="stylesheet" href="qunit/qunit.css">
|
<link rel="stylesheet" href="qunit/qunit.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="qunit"></div>
|
<div id="qunit"></div>
|
||||||
<div id="qunit-fixture"><div id="generate"></div></div>
|
<div id="qunit-fixture">
|
||||||
|
<div id="generate"></div>
|
||||||
|
</div>
|
||||||
<script src="qunit/qunit.js"></script>
|
<script src="qunit/qunit.js"></script>
|
||||||
<script src="../base64url.js"></script>
|
<script src="../base64url.js"></script>
|
||||||
<script src="../ssh-util.js"></script>
|
<script src="../ssh-util.js"></script>
|
||||||
<script src="../js-keygen.js"></script>
|
<script src="../js-keygen.js"></script>
|
||||||
<script src="tests.js"></script>
|
<script src="tests.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
382
test/tests.js
382
test/tests.js
|
@ -1,27 +1,304 @@
|
||||||
var public_ssh = ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwi36YMW0eDS3NXSAM/Gcs0txeLOcZE0LQmGPYmHX09Fm1FC9AdzvDWQIfwVylqNy8G6X8+pE0TMuWav4rQjtWRls3j43LdrXkfaTZV2PNJH0ki2zaCND3cz46hBR1bSwi3O4LoN0ZHXoC4ZXoMBXKtYEOg+9jS+pE3vu2QSPruiRROTOYYvrjWx0Bwi8DJc90TmNVeqvPjewPAm4qaTdmh96jIgJQq+vAdhDHu90i31Kl3JUF94x6pzFmg8ZyXOv0Py2GtK9c5To3C33FXI8yTm/sf2Bp7fwd3MEGNcdVNqa7Tt0z2u5Jcmsws93SZuj4iVjbR6xqme9EmIa3BTB7 name",
|
var public_ssh = [
|
||||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuew50MaphQgiuM6H7zxMspNojI2Ujf77MuWlAjmw1JxcTkfE7JKzV+9fqmESJNtnZSr3+I2dxQhJ72jttrz+2dFt9ol91muTPWzKrA8XXIBH2o7sEJ+QB8/q7S03d+Zgw6tlo+qdXLOWcKqL5MJhYwzTFEdGTSMF00cBFadcpDq1xFPygGTHRa7m3pK723nGz7TMGWmtBK2bHx+Zlp7geLK/7hl+NRG1lTyIbtdkP2T4Y81Z0bhz9kNHroUei3MFD6HvN93qMJWl3/LZZzTb++1BedNeybGKqbtsB3xp0v3c6bQy49wR3RwrAwL03AKbCwTawAufSeoXyRI+rtgZ/ name",
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwi36YMW0eDS3NXSAM/Gcs0txeLOcZE0LQmGPYmHX09Fm1FC9AdzvDWQIfwVylqNy8G6X8+pE0TMuWav4rQjtWRls3j43LdrXkfaTZV2PNJH0ki2zaCND3cz46hBR1bSwi3O4LoN0ZHXoC4ZXoMBXKtYEOg+9jS+pE3vu2QSPruiRROTOYYvrjWx0Bwi8DJc90TmNVeqvPjewPAm4qaTdmh96jIgJQq+vAdhDHu90i31Kl3JUF94x6pzFmg8ZyXOv0Py2GtK9c5To3C33FXI8yTm/sf2Bp7fwd3MEGNcdVNqa7Tt0z2u5Jcmsws93SZuj4iVjbR6xqme9EmIa3BTB7 name",
|
||||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCpNNtjZeldPuJ5ZgcjO4i6eSJb6kiuf1sULOoWaW9acwSxAfqrmN6Hn7VGg3GK3kSKJUmBKMsF2u+ECajVBec+OTMlbL7oZrYNl2neUYsI7O0G/8lpozZjADYu8CaMqVSAeTa3ORga9Ht/qgCpqXIyEcTsFSbZ45hhaZF0fXQ0GHDCkV/ylBduQHxheCe1SPBSWIO2BwqSlGx/Q76lkL/BnGdcx7xVi3h2yNbEGxqzFuPK75VADZfWria4x09rTqvu41GWIyqzFcbB7BxNImVNh6WVk/qKTcXbfWwH8ck9Cd5bX9g36QaImZ6tW8i/bl3o75bGgP2hSWpsNx8CMVn9 name"];
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuew50MaphQgiuM6H7zxMspNojI2Ujf77MuWlAjmw1JxcTkfE7JKzV+9fqmESJNtnZSr3+I2dxQhJ72jttrz+2dFt9ol91muTPWzKrA8XXIBH2o7sEJ+QB8/q7S03d+Zgw6tlo+qdXLOWcKqL5MJhYwzTFEdGTSMF00cBFadcpDq1xFPygGTHRa7m3pK723nGz7TMGWmtBK2bHx+Zlp7geLK/7hl+NRG1lTyIbtdkP2T4Y81Z0bhz9kNHroUei3MFD6HvN93qMJWl3/LZZzTb++1BedNeybGKqbtsB3xp0v3c6bQy49wR3RwrAwL03AKbCwTawAufSeoXyRI+rtgZ/ name",
|
||||||
var public_ssh_decoded = [{
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCpNNtjZeldPuJ5ZgcjO4i6eSJb6kiuf1sULOoWaW9acwSxAfqrmN6Hn7VGg3GK3kSKJUmBKMsF2u+ECajVBec+OTMlbL7oZrYNl2neUYsI7O0G/8lpozZjADYu8CaMqVSAeTa3ORga9Ht/qgCpqXIyEcTsFSbZ45hhaZF0fXQ0GHDCkV/ylBduQHxheCe1SPBSWIO2BwqSlGx/Q76lkL/BnGdcx7xVi3h2yNbEGxqzFuPK75VADZfWria4x09rTqvu41GWIyqzFcbB7BxNImVNh6WVk/qKTcXbfWwH8ck9Cd5bX9g36QaImZ6tW8i/bl3o75bGgP2hSWpsNx8CMVn9 name",
|
||||||
|
];
|
||||||
|
var public_ssh_decoded = [
|
||||||
|
{
|
||||||
type: "ssh-rsa",
|
type: "ssh-rsa",
|
||||||
exponent: [1,0,1],
|
exponent: [1, 0, 1],
|
||||||
name: "name",
|
name: "name",
|
||||||
key: [0,176,139,126,152,49,109,30,13,45,205,93,32,12,252,103,44,210,220,94,44,231,25,19,66,208,152,99,216,152,117,244,244,89,181,20,47,64,119,59,195,89,2,31,193,92,165,168,220,188,27,165,252,250,145,52,76,203,150,106,254,43,66,59,86,70,91,55,143,141,203,118,181,228,125,164,217,87,99,205,36,125,36,139,108,218,8,208,247,115,62,58,132,20,117,109,44,34,220,238,11,160,221,25,29,122,2,225,149,232,48,21,202,181,129,14,131,239,99,75,234,68,222,251,182,65,35,235,186,36,81,57,51,152,98,250,227,91,29,1,194,47,3,37,207,116,78,99,85,122,171,207,141,236,15,2,110,42,105,55,102,135,222,163,34,2,80,171,235,192,118,16,199,187,221,34,223,82,165,220,149,5,247,140,122,167,49,102,131,198,114,92,235,244,63,45,134,180,175,92,229,58,55,11,125,197,92,143,50,78,111,236,127,96,105,237,252,29,220,193,6,53,199,85,54,166,187,78,221,51,218,238,73,114,107,48,179,221,210,102,232,248,137,88,219,71,172,106,153,239,68,152,134,183,5,48,123]
|
key: [
|
||||||
}];
|
0,
|
||||||
|
176,
|
||||||
|
139,
|
||||||
|
126,
|
||||||
|
152,
|
||||||
|
49,
|
||||||
|
109,
|
||||||
|
30,
|
||||||
|
13,
|
||||||
|
45,
|
||||||
|
205,
|
||||||
|
93,
|
||||||
|
32,
|
||||||
|
12,
|
||||||
|
252,
|
||||||
|
103,
|
||||||
|
44,
|
||||||
|
210,
|
||||||
|
220,
|
||||||
|
94,
|
||||||
|
44,
|
||||||
|
231,
|
||||||
|
25,
|
||||||
|
19,
|
||||||
|
66,
|
||||||
|
208,
|
||||||
|
152,
|
||||||
|
99,
|
||||||
|
216,
|
||||||
|
152,
|
||||||
|
117,
|
||||||
|
244,
|
||||||
|
244,
|
||||||
|
89,
|
||||||
|
181,
|
||||||
|
20,
|
||||||
|
47,
|
||||||
|
64,
|
||||||
|
119,
|
||||||
|
59,
|
||||||
|
195,
|
||||||
|
89,
|
||||||
|
2,
|
||||||
|
31,
|
||||||
|
193,
|
||||||
|
92,
|
||||||
|
165,
|
||||||
|
168,
|
||||||
|
220,
|
||||||
|
188,
|
||||||
|
27,
|
||||||
|
165,
|
||||||
|
252,
|
||||||
|
250,
|
||||||
|
145,
|
||||||
|
52,
|
||||||
|
76,
|
||||||
|
203,
|
||||||
|
150,
|
||||||
|
106,
|
||||||
|
254,
|
||||||
|
43,
|
||||||
|
66,
|
||||||
|
59,
|
||||||
|
86,
|
||||||
|
70,
|
||||||
|
91,
|
||||||
|
55,
|
||||||
|
143,
|
||||||
|
141,
|
||||||
|
203,
|
||||||
|
118,
|
||||||
|
181,
|
||||||
|
228,
|
||||||
|
125,
|
||||||
|
164,
|
||||||
|
217,
|
||||||
|
87,
|
||||||
|
99,
|
||||||
|
205,
|
||||||
|
36,
|
||||||
|
125,
|
||||||
|
36,
|
||||||
|
139,
|
||||||
|
108,
|
||||||
|
218,
|
||||||
|
8,
|
||||||
|
208,
|
||||||
|
247,
|
||||||
|
115,
|
||||||
|
62,
|
||||||
|
58,
|
||||||
|
132,
|
||||||
|
20,
|
||||||
|
117,
|
||||||
|
109,
|
||||||
|
44,
|
||||||
|
34,
|
||||||
|
220,
|
||||||
|
238,
|
||||||
|
11,
|
||||||
|
160,
|
||||||
|
221,
|
||||||
|
25,
|
||||||
|
29,
|
||||||
|
122,
|
||||||
|
2,
|
||||||
|
225,
|
||||||
|
149,
|
||||||
|
232,
|
||||||
|
48,
|
||||||
|
21,
|
||||||
|
202,
|
||||||
|
181,
|
||||||
|
129,
|
||||||
|
14,
|
||||||
|
131,
|
||||||
|
239,
|
||||||
|
99,
|
||||||
|
75,
|
||||||
|
234,
|
||||||
|
68,
|
||||||
|
222,
|
||||||
|
251,
|
||||||
|
182,
|
||||||
|
65,
|
||||||
|
35,
|
||||||
|
235,
|
||||||
|
186,
|
||||||
|
36,
|
||||||
|
81,
|
||||||
|
57,
|
||||||
|
51,
|
||||||
|
152,
|
||||||
|
98,
|
||||||
|
250,
|
||||||
|
227,
|
||||||
|
91,
|
||||||
|
29,
|
||||||
|
1,
|
||||||
|
194,
|
||||||
|
47,
|
||||||
|
3,
|
||||||
|
37,
|
||||||
|
207,
|
||||||
|
116,
|
||||||
|
78,
|
||||||
|
99,
|
||||||
|
85,
|
||||||
|
122,
|
||||||
|
171,
|
||||||
|
207,
|
||||||
|
141,
|
||||||
|
236,
|
||||||
|
15,
|
||||||
|
2,
|
||||||
|
110,
|
||||||
|
42,
|
||||||
|
105,
|
||||||
|
55,
|
||||||
|
102,
|
||||||
|
135,
|
||||||
|
222,
|
||||||
|
163,
|
||||||
|
34,
|
||||||
|
2,
|
||||||
|
80,
|
||||||
|
171,
|
||||||
|
235,
|
||||||
|
192,
|
||||||
|
118,
|
||||||
|
16,
|
||||||
|
199,
|
||||||
|
187,
|
||||||
|
221,
|
||||||
|
34,
|
||||||
|
223,
|
||||||
|
82,
|
||||||
|
165,
|
||||||
|
220,
|
||||||
|
149,
|
||||||
|
5,
|
||||||
|
247,
|
||||||
|
140,
|
||||||
|
122,
|
||||||
|
167,
|
||||||
|
49,
|
||||||
|
102,
|
||||||
|
131,
|
||||||
|
198,
|
||||||
|
114,
|
||||||
|
92,
|
||||||
|
235,
|
||||||
|
244,
|
||||||
|
63,
|
||||||
|
45,
|
||||||
|
134,
|
||||||
|
180,
|
||||||
|
175,
|
||||||
|
92,
|
||||||
|
229,
|
||||||
|
58,
|
||||||
|
55,
|
||||||
|
11,
|
||||||
|
125,
|
||||||
|
197,
|
||||||
|
92,
|
||||||
|
143,
|
||||||
|
50,
|
||||||
|
78,
|
||||||
|
111,
|
||||||
|
236,
|
||||||
|
127,
|
||||||
|
96,
|
||||||
|
105,
|
||||||
|
237,
|
||||||
|
252,
|
||||||
|
29,
|
||||||
|
220,
|
||||||
|
193,
|
||||||
|
6,
|
||||||
|
53,
|
||||||
|
199,
|
||||||
|
85,
|
||||||
|
54,
|
||||||
|
166,
|
||||||
|
187,
|
||||||
|
78,
|
||||||
|
221,
|
||||||
|
51,
|
||||||
|
218,
|
||||||
|
238,
|
||||||
|
73,
|
||||||
|
114,
|
||||||
|
107,
|
||||||
|
48,
|
||||||
|
179,
|
||||||
|
221,
|
||||||
|
210,
|
||||||
|
102,
|
||||||
|
232,
|
||||||
|
248,
|
||||||
|
137,
|
||||||
|
88,
|
||||||
|
219,
|
||||||
|
71,
|
||||||
|
172,
|
||||||
|
106,
|
||||||
|
153,
|
||||||
|
239,
|
||||||
|
68,
|
||||||
|
152,
|
||||||
|
134,
|
||||||
|
183,
|
||||||
|
5,
|
||||||
|
48,
|
||||||
|
123,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
var jwk_public = {"alg":"RS1","e":"AQAB","ext":true,"key_ops":["verify"],"kty":"RSA","n":"3PWJ6uDsFPgQo67of3IYw0Svyq95SNh9GS-2gorv68GxWIYYeAShaG_UtTf8mvf6u-VIUr54Re2FoLc78ICR3nRhFH5D1_fNaP9hkMAHBqaJ8ATiq4d7-PfeXTCi0yY0qfWkGjuPtOC3IK7WmnEkiA5qUVpy0oHFPiqoAyNynWJRDFJka00JEpM1QFyF1Tz3PEGp0XlFnClY48iJG9UqXlDgaysnG3ro2sDm8ftva0IjX1Sp7Z9FyWQci-yOYfST00wKHQd7z5-Eo3cTd5M0BhcVXeR0gprdK1TTDLZLznFJQ36HYwrUFEXvTyme6vkZfNPRb0z8KPq5Gs7dujE_cw"};
|
var jwk_public = {
|
||||||
|
alg: "RS1",
|
||||||
|
e: "AQAB",
|
||||||
|
ext: true,
|
||||||
|
key_ops: ["verify"],
|
||||||
|
kty: "RSA",
|
||||||
|
n:
|
||||||
|
"3PWJ6uDsFPgQo67of3IYw0Svyq95SNh9GS-2gorv68GxWIYYeAShaG_UtTf8mvf6u-VIUr54Re2FoLc78ICR3nRhFH5D1_fNaP9hkMAHBqaJ8ATiq4d7-PfeXTCi0yY0qfWkGjuPtOC3IK7WmnEkiA5qUVpy0oHFPiqoAyNynWJRDFJka00JEpM1QFyF1Tz3PEGp0XlFnClY48iJG9UqXlDgaysnG3ro2sDm8ftva0IjX1Sp7Z9FyWQci-yOYfST00wKHQd7z5-Eo3cTd5M0BhcVXeR0gprdK1TTDLZLznFJQ36HYwrUFEXvTyme6vkZfNPRb0z8KPq5Gs7dujE_cw",
|
||||||
|
};
|
||||||
|
|
||||||
var jwk_private = {
|
var jwk_private = {
|
||||||
"kty":"RSA",
|
kty: "RSA",
|
||||||
"kid":"juliet@capulet.lit",
|
kid: "juliet@capulet.lit",
|
||||||
"use":"enc",
|
use: "enc",
|
||||||
"n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRyO125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0XOC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
|
n:
|
||||||
"e":"AQAB",
|
"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRyO125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0XOC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
|
||||||
"d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfSNkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9UvqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnuToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsurY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2ahecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
|
e: "AQAB",
|
||||||
"p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHfQP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
|
d:
|
||||||
"q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6Iedis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYKrYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
|
"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfSNkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9UvqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnuToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsurY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2ahecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
|
||||||
"dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1wY52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
|
p:
|
||||||
"dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBymXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
|
"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHfQP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
|
||||||
"qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqqabu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0oYu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"
|
q:
|
||||||
|
"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6Iedis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYKrYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
|
||||||
|
dp:
|
||||||
|
"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1wY52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
|
||||||
|
dq:
|
||||||
|
"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBymXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
|
||||||
|
qi:
|
||||||
|
"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqqabu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0oYu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8",
|
||||||
};
|
};
|
||||||
|
|
||||||
var tags = {
|
var tags = {
|
||||||
|
@ -39,14 +316,16 @@ var tags = {
|
||||||
};
|
};
|
||||||
|
|
||||||
QUnit.test("array to PEM", function(assert) {
|
QUnit.test("array to PEM", function(assert) {
|
||||||
var a = [1,2,3];
|
var a = [1, 2, 3];
|
||||||
var p = arrayToPem(a);
|
var p = arrayToPem(a);
|
||||||
var a2 = pemToArray(p);
|
var a2 = pemToArray(p);
|
||||||
assert.deepEqual(a2, a, "can you count?");
|
assert.deepEqual(a2, a, "can you count?");
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("array to String", function(assert) {
|
QUnit.test("array to String", function(assert) {
|
||||||
var a = "ssh-rsa".split('').map(function (c) {return c.charCodeAt();});
|
var a = "ssh-rsa".split("").map(function(c) {
|
||||||
|
return c.charCodeAt();
|
||||||
|
});
|
||||||
assert.equal(arrayToString(pemToArray(arrayToPem(a))), "ssh-rsa");
|
assert.equal(arrayToString(pemToArray(arrayToPem(a))), "ssh-rsa");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,62 +339,69 @@ QUnit.test("arrayToLen", function(assert) {
|
||||||
assert.deepEqual(arrayToLen(a), 66051);
|
assert.deepEqual(arrayToLen(a), 66051);
|
||||||
});
|
});
|
||||||
|
|
||||||
public_ssh.forEach(function (public, index) {
|
public_ssh.forEach(function(public, index) {
|
||||||
QUnit.test("decoding ssh public key " + index, function(assert) {
|
QUnit.test("decoding ssh public key " + index, function(assert) {
|
||||||
var key = decodePublicKey(public);
|
var key = decodePublicKey(public);
|
||||||
assert.equal(key.type, "ssh-rsa", "type");
|
assert.equal(key.type, "ssh-rsa", "type");
|
||||||
assert.equal(key.name, "name", "name");
|
assert.equal(key.name, "name", "name");
|
||||||
if(index===0) {
|
if (index === 0) {
|
||||||
assert.deepEqual(key.key, public_ssh_decoded[0].key, "key");
|
assert.deepEqual(key.key, public_ssh_decoded[0].key, "key");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("Encoding ssh public key", function (assert) {
|
QUnit.test("Encoding ssh public key", function(assert) {
|
||||||
var result = encodePublicKey(jwk_public, "name");
|
var result = encodePublicKey(jwk_public, "name");
|
||||||
assert.equal(result, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc9Ynq4OwU+BCjruh/chjDRK/Kr3lI2H0ZL7aCiu/rwbFYhhh4BKFob9S1N/ya9/q75UhSvnhF7YWgtzvwgJHedGEUfkPX981o/2GQwAcGponwBOKrh3v4995dMKLTJjSp9aQaO4+04LcgrtaacSSIDmpRWnLSgcU+KqgDI3KdYlEMUmRrTQkSkzVAXIXVPPc8QanReUWcKVjjyIkb1SpeUOBrKycbeujawObx+29rQiNfVKntn0XJZByL7I5h9JPTTAodB3vPn4SjdxN3kzQGFxVd5HSCmt0rVNMMtkvOcUlDfodjCtQURe9PKZ7q+Rl809FvTPwo+rkazt26MT9z name");
|
assert.equal(
|
||||||
|
result,
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc9Ynq4OwU+BCjruh/chjDRK/Kr3lI2H0ZL7aCiu/rwbFYhhh4BKFob9S1N/ya9/q75UhSvnhF7YWgtzvwgJHedGEUfkPX981o/2GQwAcGponwBOKrh3v4995dMKLTJjSp9aQaO4+04LcgrtaacSSIDmpRWnLSgcU+KqgDI3KdYlEMUmRrTQkSkzVAXIXVPPc8QanReUWcKVjjyIkb1SpeUOBrKycbeujawObx+29rQiNfVKntn0XJZByL7I5h9JPTTAodB3vPn4SjdxN3kzQGFxVd5HSCmt0rVNMMtkvOcUlDfodjCtQURe9PKZ7q+Rl809FvTPwo+rkazt26MT9z name"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("base64url", function (assert){
|
QUnit.test("base64url", function(assert) {
|
||||||
var result = stringToArray(base64urlDecode(jwk_public.n));
|
var result = stringToArray(base64urlDecode(jwk_public.n));
|
||||||
assert.equal(result.length, 256);
|
assert.equal(result.length, 256);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("high bit", function (assert) {
|
QUnit.test("high bit", function(assert) {
|
||||||
assert.deepEqual(checkHighestBit([0x80]), [0x00, 0x80]);
|
assert.deepEqual(checkHighestBit([0x80]), [0x00, 0x80]);
|
||||||
assert.deepEqual(checkHighestBit([0x0F]), [0x0F]);
|
assert.deepEqual(checkHighestBit([0x0f]), [0x0f]);
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("jwk", function (assert){
|
QUnit.test("jwk", function(assert) {
|
||||||
var sshkey = encodePublicKey(jwk_public, "name");
|
var sshkey = encodePublicKey(jwk_public, "name");
|
||||||
assert.deepEqual(stringToArray(base64urlDecode(jwk_public.e)), [1,0,1]);
|
assert.deepEqual(stringToArray(base64urlDecode(jwk_public.e)), [1, 0, 1]);
|
||||||
assert.equal(sshkey, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc9Ynq4OwU+BCjruh/chjDRK/Kr3lI2H0ZL7aCiu/rwbFYhhh4BKFob9S1N/ya9/q75UhSvnhF7YWgtzvwgJHedGEUfkPX981o/2GQwAcGponwBOKrh3v4995dMKLTJjSp9aQaO4+04LcgrtaacSSIDmpRWnLSgcU+KqgDI3KdYlEMUmRrTQkSkzVAXIXVPPc8QanReUWcKVjjyIkb1SpeUOBrKycbeujawObx+29rQiNfVKntn0XJZByL7I5h9JPTTAodB3vPn4SjdxN3kzQGFxVd5HSCmt0rVNMMtkvOcUlDfodjCtQURe9PKZ7q+Rl809FvTPwo+rkazt26MT9z name")
|
assert.equal(
|
||||||
|
sshkey,
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc9Ynq4OwU+BCjruh/chjDRK/Kr3lI2H0ZL7aCiu/rwbFYhhh4BKFob9S1N/ya9/q75UhSvnhF7YWgtzvwgJHedGEUfkPX981o/2GQwAcGponwBOKrh3v4995dMKLTJjSp9aQaO4+04LcgrtaacSSIDmpRWnLSgcU+KqgDI3KdYlEMUmRrTQkSkzVAXIXVPPc8QanReUWcKVjjyIkb1SpeUOBrKycbeujawObx+29rQiNfVKntn0XJZByL7I5h9JPTTAodB3vPn4SjdxN3kzQGFxVd5HSCmt0rVNMMtkvOcUlDfodjCtQURe9PKZ7q+Rl809FvTPwo+rkazt26MT9z name"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
[{len:0x01, octet:[0x01]},
|
[
|
||||||
{len:0x104, octet:[0x01, 0x04]},
|
{ len: 0x01, octet: [0x01] },
|
||||||
{len:0xFF32, octet:[0xFF,0x32]},
|
{ len: 0x104, octet: [0x01, 0x04] },
|
||||||
{len:0x1000000, octet:[1,0,0,0]},
|
{ len: 0xff32, octet: [0xff, 0x32] },
|
||||||
{len:0x7FFFFFFF, octet:[0x7F,0xFF,0xFF,0xFF]}, //biggest one
|
{ len: 0x1000000, octet: [1, 0, 0, 0] },
|
||||||
].forEach(function (t) {
|
{ len: 0x7fffffff, octet: [0x7f, 0xff, 0xff, 0xff] }, //biggest one
|
||||||
QUnit.test("Integer to Octet:" + t.len, function (assert) {
|
].forEach(function(t) {
|
||||||
|
QUnit.test("Integer to Octet:" + t.len, function(assert) {
|
||||||
assert.deepEqual(integerToOctet(t.len), t.octet, t.len);
|
assert.deepEqual(integerToOctet(t.len), t.octet, t.len);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
[{len: 0x34 , asn: [0x34]},
|
[
|
||||||
{len: 256 , asn: [0x80 + 2, 0x01, 0x00]},
|
{ len: 0x34, asn: [0x34] },
|
||||||
{len: 0x134 , asn: [0x80 + 2, 0x01, 0x34]},
|
{ len: 256, asn: [0x80 + 2, 0x01, 0x00] },
|
||||||
{len: 0x12345 , asn: [0x80 + 3, 0x01, 0x23, 0x45]},
|
{ len: 0x134, asn: [0x80 + 2, 0x01, 0x34] },
|
||||||
{len: 0x123456 , asn: [0x80 + 3, 0x12, 0x34, 0x56]},
|
{ len: 0x12345, asn: [0x80 + 3, 0x01, 0x23, 0x45] },
|
||||||
].forEach(function (t) {
|
{ len: 0x123456, asn: [0x80 + 3, 0x12, 0x34, 0x56] },
|
||||||
QUnit.test("ASN.1 Len Writing:" + t.len, function (assert) {
|
].forEach(function(t) {
|
||||||
|
QUnit.test("ASN.1 Len Writing:" + t.len, function(assert) {
|
||||||
assert.deepEqual(asnEncodeLen(t.len), t.asn, t.len);
|
assert.deepEqual(asnEncodeLen(t.len), t.asn, t.len);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
QUnit.test("encodePrivateKey", function (assert) {
|
QUnit.test("encodePrivateKey", function(assert) {
|
||||||
var encoded = encodePrivateKey(jwk_private);
|
var encoded = encodePrivateKey(jwk_private);
|
||||||
console.log(encoded);
|
console.log(encoded);
|
||||||
assert.ok(true);
|
assert.ok(true);
|
||||||
|
|
Loading…
Reference in a new issue