1 package org.bouncycastle.crypto.signers; 2 3 import java.math.BigInteger; 4 import java.security.SecureRandom; 5 6 import org.bouncycastle.crypto.CipherParameters; 7 import org.bouncycastle.crypto.DSA; 8 import org.bouncycastle.crypto.params.DSAKeyParameters; 9 import org.bouncycastle.crypto.params.DSAParameters; 10 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; 11 import org.bouncycastle.crypto.params.DSAPublicKeyParameters; 12 import org.bouncycastle.crypto.params.ParametersWithRandom; 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 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 SecureRandom providedRandom = null; 49 50 if (forSigning) 51 { 52 if (param instanceof ParametersWithRandom) 53 { 54 ParametersWithRandom rParam = (ParametersWithRandom)param; 55 56 this.key = (DSAPrivateKeyParameters)rParam.getParameters(); 57 providedRandom = rParam.getRandom(); 58 } 59 else 60 { 61 this.key = (DSAPrivateKeyParameters)param; 62 } 63 } 64 else 65 { 66 this.key = (DSAPublicKeyParameters)param; 67 } 68 69 this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); 70 } 71 72 /** 73 * generate a signature for the given message using the key we were 74 * initialised with. For conventional DSA the message should be a SHA-1 75 * hash of the message of interest. 76 * 77 * @param message the message that will be verified later. 78 */ 79 public BigInteger[] generateSignature( 80 byte[] message) 81 { 82 DSAParameters params = key.getParameters(); 83 BigInteger q = params.getQ(); 84 BigInteger m = calculateE(q, message); 85 BigInteger x = ((DSAPrivateKeyParameters)key).getX(); 86 87 if (kCalculator.isDeterministic()) 88 { 89 kCalculator.init(q, x, message); 90 } 91 else 92 { 93 kCalculator.init(q, random); 94 } 95 96 BigInteger k = kCalculator.nextK(); 97 98 // the randomizer is to conceal timing information related to k and x. 99 BigInteger r = params.getG().modPow(k.add(getRandomizer(q, random)), params.getP()).mod(q); 100 101 k = k.modInverse(q).multiply(m.add(x.multiply(r))); 102 103 BigInteger s = k.mod(q); 104 105 return new BigInteger[]{ r, s }; 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 q = params.getQ(); 120 BigInteger m = calculateE(q, message); 121 BigInteger zero = BigInteger.valueOf(0); 122 123 if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) 124 { 125 return false; 126 } 127 128 if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) 129 { 130 return false; 131 } 132 133 BigInteger w = s.modInverse(q); 134 135 BigInteger u1 = m.multiply(w).mod(q); 136 BigInteger u2 = r.multiply(w).mod(q); 137 138 BigInteger p = params.getP(); 139 u1 = params.getG().modPow(u1, p); 140 u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, p); 141 142 BigInteger v = u1.multiply(u2).mod(p).mod(q); 143 144 return v.equals(r); 145 } 146 147 private BigInteger calculateE(BigInteger n, byte[] message) 148 { 149 if (n.bitLength() >= message.length * 8) 150 { 151 return new BigInteger(1, message); 152 } 153 else 154 { 155 byte[] trunc = new byte[n.bitLength() / 8]; 156 157 System.arraycopy(message, 0, trunc, 0, trunc.length); 158 159 return new BigInteger(1, trunc); 160 } 161 } 162 163 protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) 164 { 165 return !needed ? null : (provided != null) ? provided : new SecureRandom(); 166 } 167 168 private BigInteger getRandomizer(BigInteger q, SecureRandom provided) 169 { 170 // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r. 171 int randomBits = 7; 172 173 return new BigInteger(randomBits, provided != null ? provided : new SecureRandom()).add(BigInteger.valueOf(128)).multiply(q); 174 } 175 } 176