2015-09-04 07:13:08 +00:00
|
|
|
var base64urlDecode;
|
|
|
|
|
2015-09-03 11:58:00 +00:00
|
|
|
function arrayToString(a) {
|
|
|
|
return String.fromCharCode.apply(null, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stringToArray(s) {
|
2018-02-13 08:53:20 +00:00
|
|
|
return s.split("").map(c => c.charCodeAt());
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function base64urlToArray(s) {
|
|
|
|
return stringToArray(base64urlDecode(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
function pemToArray(pem) {
|
|
|
|
return stringToArray(window.atob(pem));
|
|
|
|
}
|
|
|
|
|
|
|
|
function arrayToPem(a) {
|
2018-02-13 08:53:20 +00:00
|
|
|
return window.btoa(a.map(c => String.fromCharCode(c)).join(""));
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function arrayToLen(a) {
|
2018-02-13 08:30:29 +00:00
|
|
|
var result = 0,
|
|
|
|
i;
|
2015-09-04 07:13:08 +00:00
|
|
|
for (i = 0; i < a.length; i += 1) {
|
2015-09-03 11:58:00 +00:00
|
|
|
result = result * 256 + a[i];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
function integerToOctet(n) {
|
|
|
|
var result = [];
|
2015-09-04 07:13:08 +00:00
|
|
|
for (true; n > 0; n = n >> 8) {
|
2018-02-13 08:30:29 +00:00
|
|
|
result.push(n & 0xff);
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
return result.reverse();
|
|
|
|
}
|
|
|
|
|
|
|
|
function lenToArray(n) {
|
2018-02-13 08:30:29 +00:00
|
|
|
var oct = integerToOctet(n),
|
|
|
|
i;
|
2015-09-04 07:13:08 +00:00
|
|
|
for (i = oct.length; i < 4; i += 1) {
|
2015-09-03 11:58:00 +00:00
|
|
|
oct.unshift(0);
|
|
|
|
}
|
|
|
|
return oct;
|
|
|
|
}
|
|
|
|
|
|
|
|
function decodePublicKey(s) {
|
|
|
|
var split = s.split(" ");
|
|
|
|
var prefix = split[0];
|
2015-09-04 07:13:08 +00:00
|
|
|
if (prefix !== "ssh-rsa") {
|
2018-02-13 08:30:29 +00:00
|
|
|
throw "Unknown prefix:" + prefix;
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
var buffer = pemToArray(split[1]);
|
|
|
|
var nameLen = arrayToLen(buffer.splice(0, 4));
|
|
|
|
var type = arrayToString(buffer.splice(0, nameLen));
|
2015-09-04 07:13:08 +00:00
|
|
|
if (type !== "ssh-rsa") {
|
2018-02-13 08:30:29 +00:00
|
|
|
throw "Unknown key type:" + type;
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
var exponentLen = arrayToLen(buffer.splice(0, 4));
|
|
|
|
var exponent = buffer.splice(0, exponentLen);
|
|
|
|
var keyLen = arrayToLen(buffer.splice(0, 4));
|
|
|
|
var key = buffer.splice(0, keyLen);
|
2018-02-13 08:30:29 +00:00
|
|
|
return { type: type, exponent: exponent, key: key, name: split[2] };
|
2015-09-03 11:58:00 +00:00
|
|
|
}
|
|
|
|
|
2015-09-04 07:13:08 +00:00
|
|
|
function checkHighestBit(v) {
|
2018-02-13 08:30:29 +00:00
|
|
|
if (v[0] >> 7 === 1) {
|
|
|
|
// add leading zero if first bit is set
|
2015-09-04 07:13:08 +00:00
|
|
|
v.unshift(0);
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2015-09-03 11:58:00 +00:00
|
|
|
function jwkToInternal(jwk) {
|
|
|
|
return {
|
|
|
|
type: "ssh-rsa",
|
|
|
|
exponent: checkHighestBit(stringToArray(base64urlDecode(jwk.e))),
|
2015-09-04 07:13:08 +00:00
|
|
|
name: "name",
|
2018-02-13 08:30:29 +00:00
|
|
|
key: checkHighestBit(stringToArray(base64urlDecode(jwk.n))),
|
2015-09-03 11:58:00 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function encodePublicKey(jwk, name) {
|
|
|
|
var k = jwkToInternal(jwk);
|
|
|
|
k.name = name;
|
|
|
|
var keyLenA = lenToArray(k.key.length);
|
|
|
|
var exponentLenA = lenToArray(k.exponent.length);
|
|
|
|
var typeLenA = lenToArray(k.type.length);
|
|
|
|
var array = [].concat(typeLenA, stringToArray(k.type), exponentLenA, k.exponent, keyLenA, k.key);
|
|
|
|
var encoding = arrayToPem(array);
|
|
|
|
return k.type + " " + encoding + " " + k.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
function asnEncodeLen(n) {
|
|
|
|
var result = [];
|
2015-09-04 07:13:08 +00:00
|
|
|
if (n >> 7) {
|
2015-09-03 11:58:00 +00:00
|
|
|
result = integerToOctet(n);
|
|
|
|
result.unshift(0x80 + result.length);
|
|
|
|
} else {
|
|
|
|
result.push(n);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
function encodePrivateKey(jwk) {
|
|
|
|
var order = ["n", "e", "d", "p", "q", "dp", "dq", "qi"];
|
2018-02-13 08:53:20 +00:00
|
|
|
var list = order.map(prop => {
|
2015-09-03 11:58:00 +00:00
|
|
|
var v = checkHighestBit(stringToArray(base64urlDecode(jwk[prop])));
|
|
|
|
var len = asnEncodeLen(v.length);
|
|
|
|
return [0x02].concat(len, v); // int tag is 0x02
|
|
|
|
});
|
|
|
|
var seq = [0x02, 0x01, 0x00]; // extra seq for SSH
|
|
|
|
seq = seq.concat.apply(seq, list);
|
|
|
|
var len = asnEncodeLen(seq.length);
|
2015-09-04 07:13:08 +00:00
|
|
|
var a = [0x30].concat(len, seq); // seq is 0x30
|
2015-09-03 11:58:00 +00:00
|
|
|
return arrayToPem(a);
|
2015-09-04 07:13:08 +00:00
|
|
|
}
|
2018-02-13 08:45:06 +00:00
|
|
|
|
2018-02-13 09:49:20 +00:00
|
|
|
module = window.module || {};
|
2018-02-13 08:45:06 +00:00
|
|
|
module.exports = { base64urlToArray, decodePublicKey, encodePublicKey, encodePrivateKey };
|