diff --git a/lib/dsa.js b/lib/dsa.js index a16403f9..9b45d519 100644 --- a/lib/dsa.js +++ b/lib/dsa.js @@ -59,13 +59,19 @@ var err, hi, r, s, u1, u2, v, w; r = _arg[0], s = _arg[1]; err = null; - hi = this.trunc_hash(h); - w = s.modInverse(this.q); - u1 = hi.multiply(w).mod(this.q); - u2 = r.multiply(w).mod(this.q); - v = this.g.modPow(u1, this.p).multiply(this.y.modPow(u2, this.p)).mod(this.p).mod(this.q); - if (!v.equals(r)) { - err = new Error("verification failed"); + if ((r.signum() <= 0) || (r.compareTo(this.q) >= 0)) { + err = new Error("bad r"); + } else if ((s.signum() <= 0) || (s.compareTo(this.q) >= 0)) { + err = new Error("bad s"); + } else { + hi = this.trunc_hash(h); + w = s.modInverse(this.q); + u1 = hi.multiply(w).mod(this.q); + u2 = r.multiply(w).mod(this.q); + v = this.g.modPow(u1, this.p).multiply(this.y.modPow(u2, this.p)).mod(this.p).mod(this.q); + if (!v.equals(r)) { + err = new Error("verification failed"); + } } return cb(err); }; @@ -102,7 +108,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/dsa.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/dsa.iced", funcname: "Priv.sign" }); SRF().random_zn(q.subtract(bn.nbv(2)), __iced_deferrals.defer({ @@ -111,7 +117,7 @@ return k = arguments[0]; }; })(), - lineno: 76 + lineno: 81 })); __iced_deferrals._fulfill(); }); @@ -200,7 +206,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/dsa.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/dsa.iced", funcname: "Pair.pad_and_sign" }); _this.priv.sign(h, __iced_deferrals.defer({ @@ -209,7 +215,7 @@ return sig = arguments[0]; }; })(), - lineno: 128 + lineno: 133 })); __iced_deferrals._fulfill(); }); diff --git a/lib/ecc/ecdsa.js b/lib/ecc/ecdsa.js index 58d519f8..3088c591 100644 --- a/lib/ecc/ecdsa.js +++ b/lib/ecc/ecdsa.js @@ -57,9 +57,9 @@ r = _arg[0], s = _arg[1]; err = null; hi = this.trunc_hash(h); - if ((r.signum() <= 0) || (r.compareTo(this.curve.p) > 0)) { + if ((r.signum() <= 0) || (r.compareTo(this.curve.n) >= 0)) { err = new Error("bad r"); - } else if ((r.signum() <= 0) || (s.compareTo(this.curve.p) > 0)) { + } else if ((s.signum() <= 0) || (s.compareTo(this.curve.n) >= 0)) { err = new Error("bad s"); } else { n = this.curve.n; @@ -67,9 +67,13 @@ u1 = hi.multiply(w).mod(n); u2 = r.multiply(w).mod(n); p = this.curve.G.multiplyTwo(u1, this.R, u2); - v = p.affineX.mod(n); - if (!v.equals(r)) { + if (this.curve.isInfinity(p)) { err = new Error("verification failed"); + } else { + v = p.affineX.mod(n); + if (!v.equals(r)) { + err = new Error("verification failed"); + } } } return cb(err); @@ -107,7 +111,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/ecc/ecdsa.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/ecc/ecdsa.iced", funcname: "Priv.sign" }); _this.pub.curve.random_scalar(__iced_deferrals.defer({ @@ -116,7 +120,7 @@ return k = arguments[0]; }; })(), - lineno: 79 + lineno: 80 })); __iced_deferrals._fulfill(); }); @@ -212,7 +216,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/ecc/ecdsa.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/ecc/ecdsa.iced", funcname: "Pair.pad_and_sign" }); _this.priv.sign(h, __iced_deferrals.defer({ @@ -221,7 +225,7 @@ return sig = arguments[0]; }; })(), - lineno: 134 + lineno: 135 })); __iced_deferrals._fulfill(); }); diff --git a/lib/elgamal.js b/lib/elgamal.js index 9049e5f1..77d9027a 100644 --- a/lib/elgamal.js +++ b/lib/elgamal.js @@ -52,7 +52,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/elgamal.iced", funcname: "Pub.encrypt" }); SRF().random_zn(_this.p.subtract(bn.nbv(2)), __iced_deferrals.defer({ @@ -100,10 +100,15 @@ }; Priv.prototype.decrypt = function(c, cb) { - var p, ret; + var err, p, ret; + err = null; p = this.pub.p; - ret = c[0].modPow(this.x, p).modInverse(p).multiply(c[1]).mod(p); - return cb(null, ret); + if (((c[0].signum() <= 0) || (c[0].compareTo(p) >= 0)) || ((c[1].signum() <= 0) || (c[1].compareTo(p) >= 0))) { + err = new Error("invalid message"); + } else { + ret = c[0].modPow(this.x, p).modInverse(p).multiply(c[1]).mod(p); + } + return cb(err, ret); }; return Priv; @@ -173,7 +178,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/elgamal.iced", funcname: "Pair.pad_and_encrypt" }); eme_pkcs1_encode(data, _this.pub.p.mpi_byte_length(), __iced_deferrals.defer({ @@ -183,7 +188,7 @@ return m = arguments[1]; }; })(), - lineno: 112 + lineno: 117 })); __iced_deferrals._fulfill(); }); @@ -194,7 +199,7 @@ (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/elgamal.iced", funcname: "Pair.pad_and_encrypt" }); _this.pub.encrypt(m, __iced_deferrals.defer({ @@ -203,7 +208,7 @@ return c_mpis = arguments[0]; }; })(), - lineno: 114 + lineno: 119 })); __iced_deferrals._fulfill(); })(function() { @@ -230,7 +235,7 @@ return (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/elgamal.iced", funcname: "Pair.decrypt_and_unpad" }); _this.priv.decrypt(ciphertext.c(), __iced_deferrals.defer({ @@ -240,7 +245,7 @@ return m = arguments[1]; }; })(), - lineno: 122 + lineno: 127 })); __iced_deferrals._fulfill(); }); @@ -332,7 +337,7 @@ (function(__iced_k) { __iced_deferrals = new iced.Deferrals(__iced_k, { parent: ___iced_passed_deferral, - filename: "/Users/max/src/keybase/kbpgp/src/elgamal.iced", + filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/kbpgp/src/elgamal.iced", funcname: "Output.hide" }); key.hide({ @@ -346,7 +351,7 @@ return tmp = arguments[1]; }; })(), - lineno: 164 + lineno: 169 })); __iced_deferrals._fulfill(); })(function() { diff --git a/src/dsa.iced b/src/dsa.iced index 6ea21adc..4a2a4684 100644 --- a/src/dsa.iced +++ b/src/dsa.iced @@ -42,12 +42,17 @@ class Pub extends BaseKey verify : ([r, s], h, cb) -> err = null - hi = @trunc_hash(h) - w = s.modInverse @q - u1 = hi.multiply(w).mod(@q) - u2 = r.multiply(w).mod(@q) - v = @g.modPow(u1, @p).multiply(@y.modPow(u2, @p)).mod(@p).mod(@q) - err = new Error "verification failed" unless v.equals(r) + if ((r.signum() <= 0) or (r.compareTo(@q) >= 0)) + err = new Error "bad r" + else if ((s.signum() <= 0) or (s.compareTo(@q) >= 0)) + err = new Error "bad s" + else + hi = @trunc_hash(h) + w = s.modInverse @q + u1 = hi.multiply(w).mod(@q) + u2 = r.multiply(w).mod(@q) + v = @g.modPow(u1, @p).multiply(@y.modPow(u2, @p)).mod(@p).mod(@q) + err = new Error "verification failed" unless v.equals(r) cb err #================================================================= diff --git a/src/ecc/ecdsa.iced b/src/ecc/ecdsa.iced index df781720..444db4df 100644 --- a/src/ecc/ecdsa.iced +++ b/src/ecc/ecdsa.iced @@ -39,20 +39,21 @@ class Pub extends BaseEccKey err = null hi = @trunc_hash(h) - if ((r.signum() <= 0) or (r.compareTo(@curve.p) > 0)) + if ((r.signum() <= 0) or (r.compareTo(@curve.n) >= 0)) err = new Error "bad r" - else if ((r.signum() <= 0) or (s.compareTo(@curve.p) > 0)) + else if ((s.signum() <= 0) or (s.compareTo(@curve.n) >= 0)) err = new Error "bad s" else - n = @curve.n w = s.modInverse n u1 = hi.multiply(w).mod(n) u2 = r.multiply(w).mod(n) p = @curve.G.multiplyTwo(u1,@R,u2) - - v = p.affineX.mod(n) - err = new Error "verification failed" unless v.equals(r) + if @curve.isInfinity(p) + err = new Error "verification failed" + else + v = p.affineX.mod(n) + err = new Error "verification failed" unless v.equals(r) cb err #================================================================= diff --git a/src/elgamal.iced b/src/elgamal.iced index 31065883..bbbac69f 100644 --- a/src/elgamal.iced +++ b/src/elgamal.iced @@ -63,9 +63,14 @@ class Priv extends BaseKey #---------------- decrypt : (c, cb) -> + err = null p = @pub.p - ret = c[0].modPow(@x,p).modInverse(p).multiply(c[1]).mod(p) - cb null, ret + if ((c[0].signum() <= 0) or (c[0].compareTo(p) >= 0)) or + ((c[1].signum() <= 0) or (c[1].compareTo(p) >= 0)) + err = new Error "invalid message" + else + ret = c[0].modPow(@x,p).modInverse(p).multiply(c[1]).mod(p) + cb err, ret #================================================================= diff --git a/test/browser/main.iced b/test/browser/main.iced index fa695243..c585db92 100644 --- a/test/browser/main.iced +++ b/test/browser/main.iced @@ -1,5 +1,6 @@ mods = + bn : require '../files/bn.iced' brainpool256 : require '../files/brainpool256.iced' brainpool384: require '../files/brainpool384.iced' brainpool512: require '../files/brainpool512.iced' diff --git a/test/files/bn.iced b/test/files/bn.iced new file mode 100644 index 00000000..60bfee4b --- /dev/null +++ b/test/files/bn.iced @@ -0,0 +1,41 @@ +{nbs,BigInteger} = require '../../lib/bn' + +#================================================================= + +exports.valid_mod_inverse_returns_inverse = (T, cb) -> + cases = [ + { a : '3', m : '257', inverse : '86' } + { a : '10', m : '17', inverse : '12' } + { a : '101', m : '257', inverse : '28' } + ] + + for c in cases + a = nbs c.a + m = nbs c.m + inv = a.modInverse m + T.equal inv.toString(), c.inverse, "#{c.a}^-1 mod #{c.m}" + T.equal a.multiply(inv).mod(m).toString(), '1', "#{c.a} * inverse == 1 mod #{c.m}" + cb() + +#================================================================= + +exports.invalid_mod_inverse_returns_zero_when_gcd_is_not_one = (T, cb) -> + cases = [ + { a : '2', m : '4' } + { a : '6', m : '9' } + { a : '101', m : '101' } + { a : '202', m : '101' } + { a : '3', m : '0' } + ] + + for c in cases + a = nbs c.a + m = nbs c.m + inv = a.modInverse m + T.equal inv.signum(), 0, "#{c.a}^-1 mod #{c.m} returned zero" + T.equal inv.toString(), '0' + unless m.signum() is 0 + T.assert not(a.gcd(m).equals(BigInteger.ONE)), "#{c.a} and #{c.m} are not coprime" + cb() + +#=================================================================