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.*;
006:
007: import java.security.SecureRandom;
008: import java.math.BigInteger;
009:
010: /**
011: * GOST R 34.10-94 Signature Algorithm
012: */
013: public class GOST3410Signer implements DSA {
014: GOST3410KeyParameters key;
015:
016: SecureRandom random;
017:
018: public void init(boolean forSigning, CipherParameters param) {
019: if (forSigning) {
020: if (param instanceof ParametersWithRandom) {
021: ParametersWithRandom rParam = (ParametersWithRandom) param;
022:
023: this .random = rParam.getRandom();
024: this .key = (GOST3410PrivateKeyParameters) rParam
025: .getParameters();
026: } else {
027: this .random = new SecureRandom();
028: this .key = (GOST3410PrivateKeyParameters) param;
029: }
030: } else {
031: this .key = (GOST3410PublicKeyParameters) param;
032: }
033: }
034:
035: /**
036: * generate a signature for the given message using the key we were
037: * initialised with. For conventional GOST3410 the message should be a GOST3411
038: * hash of the message of interest.
039: *
040: * @param message the message that will be verified later.
041: */
042: public BigInteger[] generateSignature(byte[] message) {
043: byte[] mRev = new byte[message.length]; // conversion is little-endian
044: for (int i = 0; i != mRev.length; i++) {
045: mRev[i] = message[mRev.length - 1 - i];
046: }
047:
048: BigInteger m = new BigInteger(1, mRev);
049: GOST3410Parameters params = key.getParameters();
050: BigInteger k;
051:
052: do {
053: k = new BigInteger(params.getQ().bitLength(), random);
054: } while (k.compareTo(params.getQ()) >= 0);
055:
056: BigInteger r = params.getA().modPow(k, params.getP()).mod(
057: params.getQ());
058:
059: BigInteger s = k.multiply(m)
060: .add(
061: ((GOST3410PrivateKeyParameters) key).getX()
062: .multiply(r)).mod(params.getQ());
063:
064: BigInteger[] res = new BigInteger[2];
065:
066: res[0] = r;
067: res[1] = s;
068:
069: return res;
070: }
071:
072: /**
073: * return true if the value r and s represent a GOST3410 signature for
074: * the passed in message for standard GOST3410 the message should be a
075: * GOST3411 hash of the real message to be verified.
076: */
077: public boolean verifySignature(byte[] message, BigInteger r,
078: BigInteger s) {
079: byte[] mRev = new byte[message.length]; // conversion is little-endian
080: for (int i = 0; i != mRev.length; i++) {
081: mRev[i] = message[mRev.length - 1 - i];
082: }
083:
084: BigInteger m = new BigInteger(1, mRev);
085: GOST3410Parameters params = key.getParameters();
086: BigInteger zero = BigInteger.valueOf(0);
087:
088: if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0) {
089: return false;
090: }
091:
092: if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0) {
093: return false;
094: }
095:
096: BigInteger v = m.modPow(params.getQ().subtract(
097: new BigInteger("2")), params.getQ());
098:
099: BigInteger z1 = s.multiply(v).mod(params.getQ());
100: BigInteger z2 = (params.getQ().subtract(r)).multiply(v).mod(
101: params.getQ());
102:
103: z1 = params.getA().modPow(z1, params.getP());
104: z2 = ((GOST3410PublicKeyParameters) key).getY().modPow(z2,
105: params.getP());
106:
107: BigInteger u = z1.multiply(z2).mod(params.getP()).mod(
108: params.getQ());
109:
110: return u.equals(r);
111: }
112: }
|