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.ECKeyParameters;
006: import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
007: import org.bouncycastle.crypto.params.ECPublicKeyParameters;
008: import org.bouncycastle.crypto.params.ParametersWithRandom;
009: import org.bouncycastle.math.ec.ECAlgorithms;
010: import org.bouncycastle.math.ec.ECConstants;
011: import org.bouncycastle.math.ec.ECPoint;
012:
013: import java.math.BigInteger;
014: import java.security.SecureRandom;
015:
016: /**
017: * GOST R 34.10-2001 Signature Algorithm
018: */
019: public class ECGOST3410Signer implements DSA {
020: ECKeyParameters key;
021:
022: SecureRandom random;
023:
024: public void init(boolean forSigning, CipherParameters param) {
025: if (forSigning) {
026: if (param instanceof ParametersWithRandom) {
027: ParametersWithRandom rParam = (ParametersWithRandom) param;
028:
029: this .random = rParam.getRandom();
030: this .key = (ECPrivateKeyParameters) rParam
031: .getParameters();
032: } else {
033: this .random = new SecureRandom();
034: this .key = (ECPrivateKeyParameters) param;
035: }
036: } else {
037: this .key = (ECPublicKeyParameters) param;
038: }
039: }
040:
041: /**
042: * generate a signature for the given message using the key we were
043: * initialised with. For conventional GOST3410 the message should be a GOST3411
044: * hash of the message of interest.
045: *
046: * @param message the message that will be verified later.
047: */
048: public BigInteger[] generateSignature(byte[] message) {
049: byte[] mRev = new byte[message.length]; // conversion is little-endian
050: for (int i = 0; i != mRev.length; i++) {
051: mRev[i] = message[mRev.length - 1 - i];
052: }
053:
054: BigInteger e = new BigInteger(1, mRev);
055: BigInteger n = key.getParameters().getN();
056:
057: BigInteger r = null;
058: BigInteger s = null;
059:
060: do // generate s
061: {
062: BigInteger k = null;
063:
064: do // generate r
065: {
066: do {
067: k = new BigInteger(n.bitLength(), random);
068: } while (k.equals(ECConstants.ZERO));
069:
070: ECPoint p = key.getParameters().getG().multiply(k);
071:
072: BigInteger x = p.getX().toBigInteger();
073:
074: r = x.mod(n);
075: } while (r.equals(ECConstants.ZERO));
076:
077: BigInteger d = ((ECPrivateKeyParameters) key).getD();
078:
079: s = (k.multiply(e)).add(d.multiply(r)).mod(n);
080: } while (s.equals(ECConstants.ZERO));
081:
082: BigInteger[] res = new BigInteger[2];
083:
084: res[0] = r;
085: res[1] = s;
086:
087: return res;
088: }
089:
090: /**
091: * return true if the value r and s represent a GOST3410 signature for
092: * the passed in message (for standard GOST3410 the message should be
093: * a GOST3411 hash of the real message to be verified).
094: */
095: public boolean verifySignature(byte[] message, BigInteger r,
096: BigInteger s) {
097: byte[] mRev = new byte[message.length]; // conversion is little-endian
098: for (int i = 0; i != mRev.length; i++) {
099: mRev[i] = message[mRev.length - 1 - i];
100: }
101:
102: BigInteger e = new BigInteger(1, mRev);
103: BigInteger n = key.getParameters().getN();
104:
105: // r in the range [1,n-1]
106: if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0) {
107: return false;
108: }
109:
110: // s in the range [1,n-1]
111: if (s.compareTo(ECConstants.ONE) < 0 || s.compareTo(n) >= 0) {
112: return false;
113: }
114:
115: BigInteger v = e.modInverse(n);
116:
117: BigInteger z1 = s.multiply(v).mod(n);
118: BigInteger z2 = (n.subtract(r)).multiply(v).mod(n);
119:
120: ECPoint G = key.getParameters().getG(); // P
121: ECPoint Q = ((ECPublicKeyParameters) key).getQ();
122:
123: ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2);
124:
125: BigInteger R = point.getX().toBigInteger().mod(n);
126:
127: return R.equals(r);
128: }
129: }
|