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