Package freenet.crypt

Source Code of freenet.crypt.DSA

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.crypt;

import freenet.support.LogThresholdCallback;
import java.math.BigInteger;
import java.util.Random;

import net.i2p.util.NativeBigInteger;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;

/**
* Implements the Digital Signature Algorithm (DSA) described in FIPS-186
*/
public class DSA {

    private static volatile boolean logMINOR;

    static {
        Logger.registerLogThresholdCallback(new LogThresholdCallback() {

            @Override
            public void shouldUpdate() {
                logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
            }
        });
    }

  // FIXME DSAgroupBigA is 256 bits long and therefore cannot accomodate
  // all SHA-256 output's. Therefore we chop it down to 255 bits.
 
  static final BigInteger SIGNATURE_MASK =
    Util.TWO.pow(255).subtract(BigInteger.ONE);
 
  /**
   * Returns a DSA signature given a group, private key (x), a random nonce
   * (k), and the hash of the message (m).
   */
  static DSASignature sign(DSAGroup g,
      DSAPrivateKey x,
      BigInteger k,
      BigInteger m,
      RandomSource random) {
    if(k.signum() == -1) throw new IllegalArgumentException();
    if(m.signum() == -1) throw new IllegalArgumentException();
    if(g.getQ().bitLength() == 256)
      m = m.and(SIGNATURE_MASK);
    if(m.compareTo(g.getQ()) != -1)
      throw new IllegalArgumentException();
    BigInteger r=g.getG().modPow(k, g.getP()).mod(g.getQ());

    BigInteger kInv=k.modInverse(g.getQ());
    return sign(g, x, r, kInv, m, random);
  }

  public static DSASignature sign(DSAGroup g, DSAPrivateKey x, BigInteger m,
      RandomSource r) {
    BigInteger k = DSA.generateK(g, r);
    return sign(g, x, k, m, 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)
   */
  static DSASignature sign(DSAGroup g, DSAPrivateKey x,
      BigInteger r, BigInteger kInv,
      BigInteger m, RandomSource random) {
    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.warning(DSA.class, "R or S equals 0 : Weird behaviour detected, please report if seen too often.");
      return sign(g, x, generateK(g, random), m, random);
    }
    return new DSASignature(r,s);
  }

  private static BigInteger generateK(DSAGroup g, Random r){
            if(g.getQ().bitLength() < DSAGroup.Q_BIT_LENGTH)
        throw new IllegalArgumentException("Q is too short! (" + g.getQ().bitLength() + '<' + DSAGroup.Q_BIT_LENGTH + ')');
   
            BigInteger k;
    do {
      k=new NativeBigInteger(DSAGroup.Q_BIT_LENGTH, r);
    } while ((g.getQ().compareTo(k) < 1) || (k.compareTo(BigInteger.ZERO) < 1));
    return k;
  }

  /**
   * Verifies the message authenticity given a group, the public key
   * (y), a signature, and the hash of the message (m).
   * @param forceMod If enabled, skip the clipping m to 255 bits.
   */
  public static boolean verify(DSAPublicKey kp,
      DSASignature sig,
      BigInteger m, boolean forceMod) {
    if(m.signum() == -1) throw new IllegalArgumentException();
    if(kp.getGroup().getQ().bitLength() == 256 && !forceMod)
      m = m.and(SIGNATURE_MASK);
    try {
      // 0<r<q has to be true
      if((sig.getR().compareTo(BigInteger.ZERO) < 1) || (kp.getQ().compareTo(sig.getR()) < 1)) {
        if(logMINOR)
          Logger.minor(DSA.class, "r < 0 || r > q: r="+sig.getR()+" q="+kp.getQ());
        return false;
      }
      // 0<s<q has to be true as well
      if((sig.getS().compareTo(BigInteger.ZERO) < 1) || (kp.getQ().compareTo(sig.getS()) < 1)) {
        if(logMINOR)
          Logger.minor(DSA.class, "s < 0 || s > q: s="+sig.getS()+" q="+kp.getQ());
        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());

      //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
      if(logMINOR)
        Logger.minor(DSA.class, "Verify failed: "+e, e);
      return false;                  // and report that that data is bad.
    }
  }

  public static void main(String[] args) throws Exception {
    //DSAGroup g=DSAGroup.readFromField(args[0]);
    freenet.support.SimpleFieldSet fs = args.length >= 1 && args[0].length() != 0 ? freenet.support.SimpleFieldSet.readFrom(new java.io.File(args[0]), false, false) : null;
    DSAGroup g = Global.DSAgroupBigA;
    if (fs != null)
      g = DSAGroup.create(fs.subset("dsaGroup"));
    RandomSource y = new DummyRandomSource();
    if (args.length >= 2 && args[1].equals("yarrow")) y = new Yarrow();
    DSAPrivateKey pk=new DSAPrivateKey(g, y);
    DSAPublicKey pub=new DSAPublicKey(g, pk);
    if (fs != null) {
      pub = DSAPublicKey.create(fs.subset("dsaPubKey"), g);
      pk = DSAPrivateKey.create(fs.subset("dsaPrivKey"), g);
    }
    DSASignature sig=sign(g, pk, BigInteger.ZERO, y);
    System.err.println(verify(pub, sig, BigInteger.ZERO, false));
    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];
      long[] timeSigning = new long[1000];
      long[] timeVerifying = new long[timeSigning.length];
      for(int i=0;i<timeSigning.length;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.nanoTime();
        sig = sign(g, pk, m, y);
        long t2 = System.nanoTime();
        if(!verify(pub, sig, m, false)) {
          System.err.println("Failed to verify!");
        }
        long t3 = System.nanoTime();
        totalTimeSigning += (t2 - t1);
        timeSigning[i] = t2-t1;
        totalTimeVerifying += (t3 - t2);
        timeVerifying[i] = t3-t2;
        int rSize = sig.getR().bitLength();
        rSize = (rSize + 7) / 8;
        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 + 7) / 8;
        totalSSize += sSize;
        if(sSize > maxSSize) maxSSize = sSize;
      }
      System.out.println("Total time signing: "+totalTimeSigning);
      java.util.Arrays.sort(timeSigning);
      System.out.println("\tavg="+((double)totalTimeSigning/timeSigning.length)+"\tmed="+timeSigning[timeSigning.length/2]+"\tmin="+timeSigning[0]+"\tmax="+timeSigning[timeSigning.length-1]);
      System.out.println("Total time verifying: "+totalTimeVerifying);
      java.util.Arrays.sort(timeVerifying);
      System.out.println("\tavg="+((double)totalTimeVerifying/timeVerifying.length)+"\tmed="+timeVerifying[timeVerifying.length/2]+"\tmin="+timeVerifying[0]+"\tmax="+timeVerifying[timeVerifying.length-1]);
      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+ ')');
    }
    }
}
TOP

Related Classes of freenet.crypt.DSA

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.