Author: nextgens
Date: 2006-09-24 01:02:49 +0000 (Sun, 24 Sep 2006)
New Revision: 10505

Modified:
   trunk/freenet/src/freenet/crypt/DSA.java
   trunk/freenet/src/freenet/crypt/DSAGroup.java
Log:
Fix some crypto code: 
        1) we were generating the "h" parameter of the group with only a few 
bytes
        2) we weren't verifying DSA signatures as we ought to

TODO: what about following FIPS-186-3 insteed of the first version ?

Of course it needs to be carefully reviewed... and hasn't been tested ;p

Modified: trunk/freenet/src/freenet/crypt/DSA.java
===================================================================
--- trunk/freenet/src/freenet/crypt/DSA.java    2006-09-23 22:47:03 UTC (rev 
10504)
+++ trunk/freenet/src/freenet/crypt/DSA.java    2006-09-24 01:02:49 UTC (rev 
10505)
@@ -14,23 +14,20 @@
      * Returns a DSA signature given a group, private key (x), a random nonce
      * (k), and the hash of the message (m).
      */
-    public static DSASignature sign(DSAGroup g,
-                                   DSAPrivateKey x,
-                                   BigInteger k, 
-                                   BigInteger m) {
+       public static DSASignature sign(DSAGroup g,
+                       DSAPrivateKey x,
+                       BigInteger k, 
+                       BigInteger m) {
                BigInteger r=g.getG().modPow(k, g.getP()).mod(g.getQ());
-               
+
                BigInteger kInv=k.modInverse(g.getQ());
                return sign(g, x, r, kInv, m);
-    } 
-       
-    public static DSASignature sign(DSAGroup g, DSAPrivateKey x, BigInteger m,
-                                   Random r) {
-       BigInteger k;
-       do {
-           k=new NativeBigInteger(256, r);
-       } while ((k.compareTo(g.getQ())>-1) || 
(k.compareTo(BigInteger.ZERO)==0));
-       return sign(g, x, k, m);
+       } 
+
+       public static DSASignature sign(DSAGroup g, DSAPrivateKey x, BigInteger 
m,
+                       Random r) {
+               BigInteger k = DSA.generateK(g, r);
+               return sign(g, x, k, m);
     }

     /**
@@ -41,10 +38,7 @@
                BigInteger[][] result=new BigInteger[count][2];

                for (int i=0; i<count; i++) {
-                       BigInteger k;
-                       do {
-                               k=new NativeBigInteger(160, r);
-                       } while ((k.compareTo(g.getQ())>-1) || 
(k.compareTo(BigInteger.ZERO)==0));
+                       BigInteger k = DSA.generateK(g, r);

                        result[i][0] = g.getG().modPow(k, g.getP()); // r 
                        result[i][1] = k.modInverse(g.getQ()); // k^-1 
@@ -60,10 +54,20 @@
     public static DSASignature sign(DSAGroup g, DSAPrivateKey x,
                                    BigInteger r, BigInteger kInv, 
                                    BigInteger m) {
-       BigInteger s1=m.add(x.getX().multiply(r)).mod(g.getQ());
-       BigInteger s=kInv.multiply(s1).mod(g.getQ());
-       return new DSASignature(r,s);
+       BigInteger s1=m.add(x.getX().multiply(r)).mod(g.getQ());
+       BigInteger s=kInv.multiply(s1).mod(g.getQ());
+       // FIXME: the following case would involve recomputing the sig. with a 
different k 
+       if((r.compareTo(BigInteger.ZERO) == 0) || (s.compareTo(BigInteger.ZERO) 
== 0)) throw new NullPointerException("Something is wrong there!");
+       return new DSASignature(r,s);
     }
+    
+    private static BigInteger generateK(DSAGroup g, Random r){
+               BigInteger k;
+               do {
+                       k=new NativeBigInteger(DSAGroup.Q_BIT_LENGTH, r);
+               } while ((g.getQ().compareTo(k) < 1) || 
(k.compareTo(BigInteger.ZERO) == 0));
+               return k;
+    }

     /**
      * Verifies the message authenticity given a group, the public key
@@ -73,7 +77,12 @@
                                 DSASignature sig,
                                 BigInteger m) {
        try {
-           BigInteger w=sig.getS().modInverse(kp.getQ());
+               // 0<r<q has to be true
+               if((sig.getR().compareTo(BigInteger.ZERO) < 1) || 
(kp.getQ().compareTo(sig.getR()) < 1)) return false;
+               // 0<s<q has to be true as well
+               if((sig.getS().compareTo(BigInteger.ZERO) < 1) || 
(kp.getQ().compareTo(sig.getS()) < 1)) return false;
+               
+               BigInteger w=sig.getS().modInverse(kp.getQ());
            BigInteger u1=m.multiply(w).mod(kp.getQ());
            BigInteger u2=sig.getR().multiply(w).mod(kp.getQ());
            BigInteger v1=kp.getG().modPow(u1, kp.getP());
@@ -81,7 +90,6 @@
            BigInteger v=v1.multiply(v2).mod(kp.getP()).mod(kp.getQ());
            return v.equals(sig.getR());

-
            //FIXME: is there a better way to handle this exception raised on 
the 'w=' line above?
        } catch (ArithmeticException e) {  // catch error raised by invalid data
            return false;                  // and report that that data is bad.

Modified: trunk/freenet/src/freenet/crypt/DSAGroup.java
===================================================================
--- trunk/freenet/src/freenet/crypt/DSAGroup.java       2006-09-23 22:47:03 UTC 
(rev 10504)
+++ trunk/freenet/src/freenet/crypt/DSAGroup.java       2006-09-24 01:02:49 UTC 
(rev 10505)
@@ -21,6 +21,8 @@
  */
 public class DSAGroup extends CryptoKey {
        private static final long serialVersionUID = -1;
+       
+       public static final int Q_BIT_LENGTH = 160;

     private BigInteger p, q, g;

@@ -171,7 +173,7 @@

         public void run() {
             while (true) {
-                qs.addElement(makePrime(160, 80, r));
+                qs.addElement(makePrime(DSAGroup.Q_BIT_LENGTH, 80, r));
                 synchronized (this) {
                     notifyAll();
                 }
@@ -239,7 +241,7 @@
                     qg.notify();
                 }
             } else
-                q = makePrime(160, 80, r);
+                q = makePrime(DSAGroup.Q_BIT_LENGTH, 80, r);

             BigInteger X = new BigInteger(bits, r).setBit(bits - 1);

@@ -252,7 +254,7 @@
         BigInteger h;
         do {
             if ((cc++) % 5 == 0) System.err.print("+");
-            h = new NativeBigInteger(160, r);
+            h = new NativeBigInteger(bits, r);
             g = h.modPow(pmin1.divide(q), p);
         } while ((h.compareTo(p.subtract(BigInteger.ONE)) != -1)
                 || (h.compareTo(BigInteger.ONE) < 1)
@@ -267,8 +269,9 @@
         q = grp.getQ();
         g = grp.getG();
         BigInteger pmin1 = p.subtract(BigInteger.ONE);
+        // TODO: that's FIPS-186-1, we should consider implementing 3 insteed!
         boolean rv = !((p.bitLength() > 1024) || (p.bitLength() < 512))
-                && ((p.bitLength() % 64) == 0) && (q.bitLength() == 160)
+                && ((p.bitLength() % 64) == 0) && (q.bitLength() == 
DSAGroup.Q_BIT_LENGTH)
                 && (q.compareTo(p) == -1) && isPrime(p, 80) && isPrime(q, 80)
                 && pmin1.mod(q).equals(BigInteger.ZERO)
                 && (g.compareTo(BigInteger.ONE) == 1)


Reply via email to