Home | History | Annotate | Download | only in signers
      1 package org.bouncycastle.crypto.signers;
      2 
      3 import org.bouncycastle.crypto.CipherParameters;
      4 import org.bouncycastle.crypto.DSA;
      5 import org.bouncycastle.crypto.params.DSAKeyParameters;
      6 import org.bouncycastle.crypto.params.DSAParameters;
      7 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
      8 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
      9 import org.bouncycastle.crypto.params.ParametersWithRandom;
     10 
     11 import java.math.BigInteger;
     12 import java.security.SecureRandom;
     13 
     14 /**
     15  * The Digital Signature Algorithm - as described in "Handbook of Applied
     16  * Cryptography", pages 452 - 453.
     17  */
     18 public class DSASigner
     19     implements DSA
     20 {
     21     DSAKeyParameters key;
     22 
     23     SecureRandom    random;
     24 
     25     public void init(
     26         boolean                 forSigning,
     27         CipherParameters        param)
     28     {
     29         if (forSigning)
     30         {
     31             if (param instanceof ParametersWithRandom)
     32             {
     33                 ParametersWithRandom    rParam = (ParametersWithRandom)param;
     34 
     35                 this.random = rParam.getRandom();
     36                 this.key = (DSAPrivateKeyParameters)rParam.getParameters();
     37             }
     38             else
     39             {
     40                 this.random = new SecureRandom();
     41                 this.key = (DSAPrivateKeyParameters)param;
     42             }
     43         }
     44         else
     45         {
     46             this.key = (DSAPublicKeyParameters)param;
     47         }
     48     }
     49 
     50     /**
     51      * generate a signature for the given message using the key we were
     52      * initialised with. For conventional DSA the message should be a SHA-1
     53      * hash of the message of interest.
     54      *
     55      * @param message the message that will be verified later.
     56      */
     57     public BigInteger[] generateSignature(
     58         byte[] message)
     59     {
     60         DSAParameters   params = key.getParameters();
     61         BigInteger      m = calculateE(params.getQ(), message);
     62         BigInteger      k;
     63         int                  qBitLength = params.getQ().bitLength();
     64 
     65         do
     66         {
     67             k = new BigInteger(qBitLength, random);
     68         }
     69         while (k.compareTo(params.getQ()) >= 0);
     70 
     71         BigInteger  r = params.getG().modPow(k, params.getP()).mod(params.getQ());
     72 
     73         k = k.modInverse(params.getQ()).multiply(
     74                     m.add(((DSAPrivateKeyParameters)key).getX().multiply(r)));
     75 
     76         BigInteger  s = k.mod(params.getQ());
     77 
     78         BigInteger[]  res = new BigInteger[2];
     79 
     80         res[0] = r;
     81         res[1] = s;
     82 
     83         return res;
     84     }
     85 
     86     /**
     87      * return true if the value r and s represent a DSA signature for
     88      * the passed in message for standard DSA the message should be a
     89      * SHA-1 hash of the real message to be verified.
     90      */
     91     public boolean verifySignature(
     92         byte[]      message,
     93         BigInteger  r,
     94         BigInteger  s)
     95     {
     96         DSAParameters   params = key.getParameters();
     97         BigInteger      m = calculateE(params.getQ(), message);
     98         BigInteger      zero = BigInteger.valueOf(0);
     99 
    100         if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0)
    101         {
    102             return false;
    103         }
    104 
    105         if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0)
    106         {
    107             return false;
    108         }
    109 
    110         BigInteger  w = s.modInverse(params.getQ());
    111 
    112         BigInteger  u1 = m.multiply(w).mod(params.getQ());
    113         BigInteger  u2 = r.multiply(w).mod(params.getQ());
    114 
    115         u1 = params.getG().modPow(u1, params.getP());
    116         u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP());
    117 
    118         BigInteger  v = u1.multiply(u2).mod(params.getP()).mod(params.getQ());
    119 
    120         return v.equals(r);
    121     }
    122 
    123     private BigInteger calculateE(BigInteger n, byte[] message)
    124     {
    125         if (n.bitLength() >= message.length * 8)
    126         {
    127             return new BigInteger(1, message);
    128         }
    129         else
    130         {
    131             byte[] trunc = new byte[n.bitLength() / 8];
    132 
    133             System.arraycopy(message, 0, trunc, 0, trunc.length);
    134 
    135             return new BigInteger(1, trunc);
    136         }
    137     }
    138 }
    139