Author: nextgens
Date: 2006-09-24 16:42:23 +0000 (Sun, 24 Sep 2006)
New Revision: 10511
Modified:
trunk/freenet/src/freenet/crypt/DSA.java
Log:
More work on our DSA code : handle the unlikely case where R or S is equal to
zero : retry a new signature with a different K
Modified: trunk/freenet/src/freenet/crypt/DSA.java
===================================================================
--- trunk/freenet/src/freenet/crypt/DSA.java 2006-09-24 12:37:09 UTC (rev
10510)
+++ trunk/freenet/src/freenet/crypt/DSA.java 2006-09-24 16:42:23 UTC (rev
10511)
@@ -3,6 +3,8 @@
import java.math.BigInteger;
import java.util.Random;
+import freenet.support.Logger;
+
import net.i2p.util.NativeBigInteger;
/**
@@ -10,10 +12,10 @@
*/
public class DSA {
- /**
- * Returns a DSA signature given a group, private key (x), a random nonce
- * (k), and the hash of the message (m).
- */
+ /**
+ * 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,
@@ -28,137 +30,139 @@
Random r) {
BigInteger k = DSA.generateK(g, r);
return sign(g, x, k, m);
- }
+ }
- /**
- * Precalculates a number of r, kInv pairs given a random source
- */
- public static BigInteger[][] signaturePrecalculate(DSAGroup g,
- int count, Random r) {
+ /**
+ * Precalculates a number of r, kInv pairs given a random source
+ */
+ public static BigInteger[][] signaturePrecalculate(DSAGroup g,
+ int count, Random r) {
BigInteger[][] result=new BigInteger[count][2];
-
+
for (int i=0; i<count; i++) {
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
}
return result;
- }
+ }
- /**
- * Returns a DSA signature given a group, private key (x),
- * the precalculated values of r and k^-1, and the hash
- * of the message (m)
- */
- 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());
- // 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){
+ /**
+ * Returns a DSA signature given a group, private key (x),
+ * the precalculated values of r and k^-1, and the hash
+ * of the message (m)
+ */
+ 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());
+ if((r.compareTo(BigInteger.ZERO) == 0) ||
(s.compareTo(BigInteger.ZERO) == 0)) {
+ Logger.normal(DSA.class, "R or S equals 0 : Weird
behaviour detected, please report if seen too often.");
+ return sign(g, x, r, generateK(g, new Random()), m);
+ }
+ 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
- * (y), a signature, and the hash of the message (m).
- */
- public static boolean verify(DSAPublicKey kp,
- DSASignature sig,
- BigInteger m) {
- try {
- // 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());
- BigInteger v2=kp.getY().modPow(u2, kp.getP());
- BigInteger v=v1.multiply(v2).mod(kp.getP()).mod(kp.getQ());
- return v.equals(sig.getR());
+ /**
+ * Verifies the message authenticity given a group, the public key
+ * (y), a signature, and the hash of the message (m).
+ */
+ public static boolean verify(DSAPublicKey kp,
+ DSASignature sig,
+ BigInteger m) {
+ try {
+ // 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;
- //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.
+ 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());
+ BigInteger v2=kp.getY().modPow(u2, kp.getP());
+ 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.
+ }
}
- }
- public static void main(String[] args) throws Exception {
- //DSAGroup g=DSAGroup.readFromField(args[0]);
- DSAGroup g = Global.DSAgroupBigA;
- //Yarrow y=new Yarrow();
- DummyRandomSource y = new DummyRandomSource();
- DSAPrivateKey pk=new DSAPrivateKey(g, y);
- DSAPublicKey pub=new DSAPublicKey(g, pk);
- DSASignature sig=sign(g, pk, BigInteger.ZERO, y);
- System.err.println(verify(pub, sig, BigInteger.ZERO));
- while(true) {
- long totalTimeSigning = 0;
- long totalTimeVerifying = 0;
- long totalRSize = 0;
- long totalSSize = 0;
- long totalPubKeySize = 0;
- long totalPrivKeySize = 0;
- int maxPrivKeySize = 0;
- int maxPubKeySize = 0;
- int maxRSize = 0;
- int maxSSize = 0;
- int totalRUnsignedBitSize = 0;
- int maxRUnsignedBitSize = 0;
- Random r = new Random(y.nextLong());
- byte[] msg = new byte[32];
- for(int i=0;i<1000;i++) {
- r.nextBytes(msg);
- BigInteger m = new BigInteger(1, msg);
- pk = new DSAPrivateKey(g, r);
- int privKeySize = pk.asBytes().length;
- totalPrivKeySize += privKeySize;
- if(privKeySize > maxPrivKeySize) maxPrivKeySize = privKeySize;
- pub = new DSAPublicKey(g, pk);
- int pubKeySize = pub.asBytes().length;
- totalPubKeySize += pubKeySize;
- if(pubKeySize > maxPubKeySize) maxPubKeySize = pubKeySize;
- long t1 = System.currentTimeMillis();
- sig = sign(g, pk, m, y);
- long t2 = System.currentTimeMillis();
- if(!verify(pub, sig, m)) {
- System.err.println("Failed to verify!");
- }
- long t3 = System.currentTimeMillis();
- totalTimeSigning += (t2 - t1);
- totalTimeVerifying += (t3 - t2);
- int rSize = sig.getR().bitLength();
- rSize = (rSize / 8) + (rSize % 8 == 0 ? 0 : 1);
- totalRSize += rSize;
- if(rSize > maxRSize) maxRSize = rSize;
- int rUnsignedBitSize = sig.getR().bitLength();
- totalRUnsignedBitSize += rUnsignedBitSize;
- maxRUnsignedBitSize = Math.max(maxRUnsignedBitSize,
rUnsignedBitSize);
- int sSize = sig.getS().bitLength();
- sSize = sSize / 8 + (sSize % 8 == 0 ? 0 : 1);
- totalSSize += sSize;
- if(sSize > maxSSize) maxSSize = sSize;
- }
- System.out.println("Total time signing: "+totalTimeSigning);
- System.out.println("Total time verifying: "+totalTimeVerifying);
- System.out.println("Total R size: "+totalRSize+" (max "+maxRSize+")");
- System.out.println("Total S size: "+totalSSize+" (max "+maxSSize+")");
- System.out.println("Total R unsigned bitsize: "+totalRUnsignedBitSize);
- System.out.println("Total pub key size: "+totalPubKeySize+" (max
"+maxPubKeySize+")");
- System.out.println("Total priv key size: "+totalPrivKeySize+" (max
"+maxPrivKeySize+")");
- }
+ public static void main(String[] args) throws Exception {
+ //DSAGroup g=DSAGroup.readFromField(args[0]);
+ DSAGroup g = Global.DSAgroupBigA;
+ //Yarrow y=new Yarrow();
+ DummyRandomSource y = new DummyRandomSource();
+ DSAPrivateKey pk=new DSAPrivateKey(g, y);
+ DSAPublicKey pub=new DSAPublicKey(g, pk);
+ DSASignature sig=sign(g, pk, BigInteger.ZERO, y);
+ System.err.println(verify(pub, sig, BigInteger.ZERO));
+ while(true) {
+ long totalTimeSigning = 0;
+ long totalTimeVerifying = 0;
+ long totalRSize = 0;
+ long totalSSize = 0;
+ long totalPubKeySize = 0;
+ long totalPrivKeySize = 0;
+ int maxPrivKeySize = 0;
+ int maxPubKeySize = 0;
+ int maxRSize = 0;
+ int maxSSize = 0;
+ int totalRUnsignedBitSize = 0;
+ int maxRUnsignedBitSize = 0;
+ Random r = new Random(y.nextLong());
+ byte[] msg = new byte[32];
+ for(int i=0;i<1000;i++) {
+ r.nextBytes(msg);
+ BigInteger m = new BigInteger(1, msg);
+ pk = new DSAPrivateKey(g, r);
+ int privKeySize = pk.asBytes().length;
+ totalPrivKeySize += privKeySize;
+ if(privKeySize > maxPrivKeySize) maxPrivKeySize
= privKeySize;
+ pub = new DSAPublicKey(g, pk);
+ int pubKeySize = pub.asBytes().length;
+ totalPubKeySize += pubKeySize;
+ if(pubKeySize > maxPubKeySize) maxPubKeySize =
pubKeySize;
+ long t1 = System.currentTimeMillis();
+ sig = sign(g, pk, m, y);
+ long t2 = System.currentTimeMillis();
+ if(!verify(pub, sig, m)) {
+ System.err.println("Failed to verify!");
+ }
+ long t3 = System.currentTimeMillis();
+ totalTimeSigning += (t2 - t1);
+ totalTimeVerifying += (t3 - t2);
+ int rSize = sig.getR().bitLength();
+ rSize = (rSize / 8) + (rSize % 8 == 0 ? 0 : 1);
+ totalRSize += rSize;
+ if(rSize > maxRSize) maxRSize = rSize;
+ int rUnsignedBitSize = sig.getR().bitLength();
+ totalRUnsignedBitSize += rUnsignedBitSize;
+ maxRUnsignedBitSize =
Math.max(maxRUnsignedBitSize, rUnsignedBitSize);
+ int sSize = sig.getS().bitLength();
+ sSize = sSize / 8 + (sSize % 8 == 0 ? 0 : 1);
+ totalSSize += sSize;
+ if(sSize > maxSSize) maxSSize = sSize;
+ }
+ System.out.println("Total time signing:
"+totalTimeSigning);
+ System.out.println("Total time verifying:
"+totalTimeVerifying);
+ System.out.println("Total R size: "+totalRSize+" (max
"+maxRSize+")");
+ System.out.println("Total S size: "+totalSSize+" (max
"+maxSSize+")");
+ System.out.println("Total R unsigned bitsize:
"+totalRUnsignedBitSize);
+ System.out.println("Total pub key size:
"+totalPubKeySize+" (max "+maxPubKeySize+")");
+ System.out.println("Total priv key size:
"+totalPrivKeySize+" (max "+maxPrivKeySize+")");
+ }
}
}