Index: lib/rsa.js |
diff --git a/lib/rsa.js b/lib/rsa.js |
index 6c6638cb266a491b0813a3169534c61f4aba9d48..2ce76818c156636898cf9b8f23b525a2567a2069 100644 |
--- a/lib/rsa.js |
+++ b/lib/rsa.js |
@@ -15,6 +15,10 @@ |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
+/* globals atob, console */ |
+ |
+"use strict"; |
+ |
/** |
* This is a specialized RSA library meant only to verify SHA1-based signatures. |
*/ |
@@ -25,9 +29,9 @@ let Rusha = require("rusha"); |
let rusha = new Rusha(); |
// Define ASN.1 templates for the data structures used |
-function seq() |
+function seq(...args) |
{ |
- return {type: 0x30, children: Array.prototype.slice.call(arguments)}; |
+ return {type: 0x30, children: args}; |
} |
function obj(id) |
{ |
@@ -48,22 +52,30 @@ function octetResult(id) |
// See http://www.cryptopp.com/wiki/Keys_and_Formats#RSA_PublicKey |
// 2A 86 48 86 F7 0D 01 01 01 means 1.2.840.113549.1.1.1 |
-var publicKeyTemplate = seq(seq(obj("\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"), {}), bitStr(seq(intResult("n"), intResult("e")))); |
+let publicKeyTemplate = seq( |
+ seq(obj("\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"), {}), |
+ bitStr(seq(intResult("n"), intResult("e"))) |
+); |
// See http://tools.ietf.org/html/rfc3447#section-9.2 step 2 |
// 2B 0E 03 02 1A means 1.3.14.3.2.26 |
-var signatureTemplate = seq(seq(obj("\x2B\x0E\x03\x02\x1A"), {}), octetResult("sha1")); |
+let signatureTemplate = seq( |
+ seq(obj("\x2B\x0E\x03\x02\x1A"), {}), |
+ octetResult("sha1") |
+); |
/** |
* Reads ASN.1 data matching the template passed in. This will throw an |
* exception if the data format doesn't match the template. On success an |
* object containing result properties is returned. |
- * |
- * See http://luca.ntop.org/Teaching/Appunti/asn1.html for info on the format. |
+ * @see http://luca.ntop.org/Teaching/Appunti/asn1.html for info on the format. |
+ * @param {String} data |
+ * @param {Object} templ |
+ * @returns {Object} |
*/ |
function readASN1(data, templ) |
{ |
- var pos = 0; |
+ let pos = 0; |
function next() |
{ |
return data.charCodeAt(pos++); |
@@ -71,26 +83,25 @@ function readASN1(data, templ) |
function readLength() |
{ |
- var len = next(); |
+ let len = next(); |
if (len & 0x80) |
{ |
- var cnt = len & 0x7F; |
+ let cnt = len & 0x7F; |
if (cnt > 2 || cnt == 0) |
throw "Unsupported length"; |
len = 0; |
- for (var i = 0; i < cnt; i++) |
+ for (let i = 0; i < cnt; i++) |
len += next() << (cnt - 1 - i) * 8; |
return len; |
} |
- else |
- return len; |
+ return len; |
} |
function readNode(curTempl) |
{ |
- var type = next(); |
- var len = readLength(); |
+ let type = next(); |
+ let len = readLength(); |
if ("type" in curTempl && curTempl.type != type) |
throw "Unexpected type"; |
if ("content" in curTempl && curTempl.content != data.substr(pos, len)) |
@@ -99,7 +110,8 @@ function readASN1(data, templ) |
out[curTempl.out] = new BigInteger(data.substr(pos, len), 256); |
if ("children" in curTempl) |
{ |
- var i, end; |
+ let i; |
+ let end; |
for (i = 0, end = pos + len; pos < end; i++) |
{ |
if (i >= curTempl.children.length) |
@@ -121,7 +133,7 @@ function readASN1(data, templ) |
pos += len; |
} |
- var out = {}; |
+ let out = {}; |
readNode(templ); |
if (pos != data.length) |
throw "Too much data"; |
@@ -131,6 +143,8 @@ function readASN1(data, templ) |
/** |
* Reads a BER-encoded RSA public key. On success returns an object with the |
* properties n and e (the components of the key), otherwise null. |
+ * @param {String} key |
+ * @return {Object|null} |
*/ |
function readPublicKey(key) |
{ |
@@ -140,17 +154,21 @@ function readPublicKey(key) |
} |
catch (e) |
{ |
- console.log("Invalid RSA public key: " + e); |
+ console.warn("Invalid RSA public key: " + e); |
return null; |
} |
} |
/** |
* Checks whether the signature is valid for the given public key and data. |
+ * @param {String} key |
+ * @param {String} signature |
+ * @param {String} data |
+ * @return {Boolean} |
*/ |
function verifySignature(key, signature, data) |
{ |
- var keyData = readPublicKey(key); |
+ let keyData = readPublicKey(key); |
if (!keyData) |
return false; |
@@ -158,33 +176,33 @@ function verifySignature(key, signature, data) |
keyData.e = parseInt(keyData.e.toString(16), 16); |
// Decrypt signature data using RSA algorithm |
- var sigInt = new BigInteger(atob(signature), 256); |
- var digest = sigInt.modPowInt(keyData.e, keyData.n).toString(256); |
+ let sigInt = new BigInteger(atob(signature), 256); |
+ let digest = sigInt.modPowInt(keyData.e, keyData.n).toString(256); |
try |
{ |
- var pos = 0; |
- function next() |
- { |
- return digest.charCodeAt(pos++); |
- } |
+ let pos = 0; |
+ let next = () => digest.charCodeAt(pos++); |
// Skip padding, see http://tools.ietf.org/html/rfc3447#section-9.2 step 5 |
if (next() != 1) |
throw "Wrong padding in signature digest"; |
- while (next() == 255) {} |
+ while (next() == 255) |
+ { |
+ // Empty |
+ } |
if (digest.charCodeAt(pos - 1) != 0) |
throw "Wrong padding in signature digest"; |
// Rest is an ASN.1 structure, get the SHA1 hash from it and compare to |
// the real one |
- var sha1 = readASN1(digest.substr(pos), signatureTemplate).sha1; |
- var expected = new BigInteger(rusha.digest(data), 16); |
+ let {sha1} = readASN1(digest.substr(pos), signatureTemplate); |
+ let expected = new BigInteger(rusha.digest(data), 16); |
return (sha1.compareTo(expected) == 0); |
} |
catch (e) |
{ |
- console.log("Invalid encrypted signature: " + e); |
+ console.warn("Invalid encrypted signature: " + e); |
return false; |
} |
} |