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 */ DSASigner()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 */ DSASigner(DSAKCalculator kCalculator)39 public DSASigner(DSAKCalculator kCalculator) 40 { 41 this.kCalculator = kCalculator; 42 } 43 init( boolean forSigning, CipherParameters param)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 */ generateSignature( byte[] message)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 BigInteger r = params.getG().modPow(k, params.getP()).mod(q); 99 100 k = k.modInverse(q).multiply(m.add(x.multiply(r))); 101 102 BigInteger s = k.mod(q); 103 104 return new BigInteger[]{ r, s }; 105 } 106 107 /** 108 * return true if the value r and s represent a DSA signature for 109 * the passed in message for standard DSA the message should be a 110 * SHA-1 hash of the real message to be verified. 111 */ verifySignature( byte[] message, BigInteger r, BigInteger s)112 public boolean verifySignature( 113 byte[] message, 114 BigInteger r, 115 BigInteger s) 116 { 117 DSAParameters params = key.getParameters(); 118 BigInteger q = params.getQ(); 119 BigInteger m = calculateE(q, message); 120 BigInteger zero = BigInteger.valueOf(0); 121 122 if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) 123 { 124 return false; 125 } 126 127 if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) 128 { 129 return false; 130 } 131 132 BigInteger w = s.modInverse(q); 133 134 BigInteger u1 = m.multiply(w).mod(q); 135 BigInteger u2 = r.multiply(w).mod(q); 136 137 BigInteger p = params.getP(); 138 u1 = params.getG().modPow(u1, p); 139 u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, p); 140 141 BigInteger v = u1.multiply(u2).mod(p).mod(q); 142 143 return v.equals(r); 144 } 145 calculateE(BigInteger n, byte[] message)146 private BigInteger calculateE(BigInteger n, byte[] message) 147 { 148 if (n.bitLength() >= message.length * 8) 149 { 150 return new BigInteger(1, message); 151 } 152 else 153 { 154 byte[] trunc = new byte[n.bitLength() / 8]; 155 156 System.arraycopy(message, 0, trunc, 0, trunc.length); 157 158 return new BigInteger(1, trunc); 159 } 160 } 161 initSecureRandom(boolean needed, SecureRandom provided)162 protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) 163 { 164 return !needed ? null : (provided != null) ? provided : new SecureRandom(); 165 } 166 } 167