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