001: package org.bouncycastle.crypto.signers;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.DSA;
005: import org.bouncycastle.crypto.params.DSAKeyParameters;
006: import org.bouncycastle.crypto.params.DSAParameters;
007: import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
008: import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
009: import org.bouncycastle.crypto.params.ParametersWithRandom;
010:
011: import java.math.BigInteger;
012: import java.security.SecureRandom;
013:
014: /**
015: * The Digital Signature Algorithm - as described in "Handbook of Applied
016: * Cryptography", pages 452 - 453.
017: */
018: public class DSASigner implements DSA {
019: DSAKeyParameters key;
020:
021: SecureRandom random;
022:
023: public void init(boolean forSigning, CipherParameters param) {
024: if (forSigning) {
025: if (param instanceof ParametersWithRandom) {
026: ParametersWithRandom rParam = (ParametersWithRandom) param;
027:
028: this .random = rParam.getRandom();
029: this .key = (DSAPrivateKeyParameters) rParam
030: .getParameters();
031: } else {
032: this .random = new SecureRandom();
033: this .key = (DSAPrivateKeyParameters) param;
034: }
035: } else {
036: this .key = (DSAPublicKeyParameters) param;
037: }
038: }
039:
040: /**
041: * generate a signature for the given message using the key we were
042: * initialised with. For conventional DSA the message should be a SHA-1
043: * hash of the message of interest.
044: *
045: * @param message the message that will be verified later.
046: */
047: public BigInteger[] generateSignature(byte[] message) {
048: DSAParameters params = key.getParameters();
049: BigInteger m = calculateE(params.getQ(), message);
050: BigInteger k;
051: int qBitLength = params.getQ().bitLength();
052:
053: do {
054: k = new BigInteger(qBitLength, random);
055: } while (k.compareTo(params.getQ()) >= 0);
056:
057: BigInteger r = params.getG().modPow(k, params.getP()).mod(
058: params.getQ());
059:
060: k = k.modInverse(params.getQ()).multiply(
061: m.add(((DSAPrivateKeyParameters) key).getX()
062: .multiply(r)));
063:
064: BigInteger s = k.mod(params.getQ());
065:
066: BigInteger[] res = new BigInteger[2];
067:
068: res[0] = r;
069: res[1] = s;
070:
071: return res;
072: }
073:
074: /**
075: * return true if the value r and s represent a DSA signature for
076: * the passed in message for standard DSA the message should be a
077: * SHA-1 hash of the real message to be verified.
078: */
079: public boolean verifySignature(byte[] message, BigInteger r,
080: BigInteger s) {
081: DSAParameters params = key.getParameters();
082: BigInteger m = calculateE(params.getQ(), message);
083: BigInteger zero = BigInteger.valueOf(0);
084:
085: if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0) {
086: return false;
087: }
088:
089: if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0) {
090: return false;
091: }
092:
093: BigInteger w = s.modInverse(params.getQ());
094:
095: BigInteger u1 = m.multiply(w).mod(params.getQ());
096: BigInteger u2 = r.multiply(w).mod(params.getQ());
097:
098: u1 = params.getG().modPow(u1, params.getP());
099: u2 = ((DSAPublicKeyParameters) key).getY().modPow(u2,
100: params.getP());
101:
102: BigInteger v = u1.multiply(u2).mod(params.getP()).mod(
103: params.getQ());
104:
105: return v.equals(r);
106: }
107:
108: private BigInteger calculateE(BigInteger n, byte[] message) {
109: if (n.bitLength() >= message.length * 8) {
110: return new BigInteger(1, message);
111: } else {
112: byte[] trunc = new byte[n.bitLength() / 8];
113:
114: System.arraycopy(message, 0, trunc, 0, trunc.length);
115:
116: return new BigInteger(1, trunc);
117: }
118: }
119: }
|