| package org.bouncycastle.crypto.signers; |
| |
| import java.math.BigInteger; |
| import java.security.SecureRandom; |
| |
| import org.bouncycastle.crypto.CipherParameters; |
| import org.bouncycastle.crypto.DSA; |
| import org.bouncycastle.crypto.params.ECDomainParameters; |
| import org.bouncycastle.crypto.params.ECKeyParameters; |
| import org.bouncycastle.crypto.params.ECPrivateKeyParameters; |
| import org.bouncycastle.crypto.params.ECPublicKeyParameters; |
| import org.bouncycastle.crypto.params.ParametersWithRandom; |
| import org.bouncycastle.math.ec.ECAlgorithms; |
| import org.bouncycastle.math.ec.ECCurve; |
| import org.bouncycastle.math.ec.ECFieldElement; |
| import org.bouncycastle.math.ec.ECMultiplier; |
| import org.bouncycastle.math.ec.ECPoint; |
| import org.bouncycastle.math.ec.FixedPointCombMultiplier; |
| import org.bouncycastle.util.Arrays; |
| |
| /** |
| * DSTU 4145-2002 |
| * <p> |
| * National Ukrainian standard of digital signature based on elliptic curves (DSTU 4145-2002). |
| * </p> |
| */ |
| public class DSTU4145Signer |
| implements DSA |
| { |
| private static final BigInteger ONE = BigInteger.valueOf(1); |
| |
| private ECKeyParameters key; |
| private SecureRandom random; |
| |
| public void init(boolean forSigning, CipherParameters param) |
| { |
| if (forSigning) |
| { |
| if (param instanceof ParametersWithRandom) |
| { |
| ParametersWithRandom rParam = (ParametersWithRandom)param; |
| |
| this.random = rParam.getRandom(); |
| param = rParam.getParameters(); |
| } |
| else |
| { |
| this.random = new SecureRandom(); |
| } |
| |
| this.key = (ECPrivateKeyParameters)param; |
| } |
| else |
| { |
| this.key = (ECPublicKeyParameters)param; |
| } |
| |
| } |
| |
| public BigInteger[] generateSignature(byte[] message) |
| { |
| ECDomainParameters ec = key.getParameters(); |
| |
| ECCurve curve = ec.getCurve(); |
| |
| ECFieldElement h = hash2FieldElement(curve, message); |
| if (h.isZero()) |
| { |
| h = curve.fromBigInteger(ONE); |
| } |
| |
| BigInteger n = ec.getN(); |
| BigInteger e, r, s; |
| ECFieldElement Fe, y; |
| |
| BigInteger d = ((ECPrivateKeyParameters)key).getD(); |
| |
| ECMultiplier basePointMultiplier = createBasePointMultiplier(); |
| |
| do |
| { |
| do |
| { |
| do |
| { |
| e = generateRandomInteger(n, random); |
| Fe = basePointMultiplier.multiply(ec.getG(), e).normalize().getAffineXCoord(); |
| } |
| while (Fe.isZero()); |
| |
| y = h.multiply(Fe); |
| r = fieldElement2Integer(n, y); |
| } |
| while (r.signum() == 0); |
| |
| s = r.multiply(d).add(e).mod(n); |
| } |
| while (s.signum() == 0); |
| |
| return new BigInteger[]{r, s}; |
| } |
| |
| public boolean verifySignature(byte[] message, BigInteger r, BigInteger s) |
| { |
| if (r.signum() <= 0 || s.signum() <= 0) |
| { |
| return false; |
| } |
| |
| ECDomainParameters parameters = key.getParameters(); |
| |
| BigInteger n = parameters.getN(); |
| if (r.compareTo(n) >= 0 || s.compareTo(n) >= 0) |
| { |
| return false; |
| } |
| |
| ECCurve curve = parameters.getCurve(); |
| |
| ECFieldElement h = hash2FieldElement(curve, message); |
| if (h.isZero()) |
| { |
| h = curve.fromBigInteger(ONE); |
| } |
| |
| ECPoint R = ECAlgorithms.sumOfTwoMultiplies(parameters.getG(), s, ((ECPublicKeyParameters)key).getQ(), r).normalize(); |
| |
| // components must be bogus. |
| if (R.isInfinity()) |
| { |
| return false; |
| } |
| |
| ECFieldElement y = h.multiply(R.getAffineXCoord()); |
| return fieldElement2Integer(n, y).compareTo(r) == 0; |
| } |
| |
| protected ECMultiplier createBasePointMultiplier() |
| { |
| return new FixedPointCombMultiplier(); |
| } |
| |
| /** |
| * Generates random integer such, than its bit length is less than that of n |
| */ |
| private static BigInteger generateRandomInteger(BigInteger n, SecureRandom random) |
| { |
| return new BigInteger(n.bitLength() - 1, random); |
| } |
| |
| private static ECFieldElement hash2FieldElement(ECCurve curve, byte[] hash) |
| { |
| byte[] data = Arrays.reverse(hash); |
| return curve.fromBigInteger(truncate(new BigInteger(1, data), curve.getFieldSize())); |
| } |
| |
| private static BigInteger fieldElement2Integer(BigInteger n, ECFieldElement fe) |
| { |
| return truncate(fe.toBigInteger(), n.bitLength() - 1); |
| } |
| |
| private static BigInteger truncate(BigInteger x, int bitLength) |
| { |
| if (x.bitLength() > bitLength) |
| { |
| x = x.mod(ONE.shiftLeft(bitLength)); |
| } |
| return x; |
| } |
| } |