package org.bouncycastle.crypto.agreement; import java.math.BigInteger; import org.bouncycastle.crypto.BasicAgreement; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.MQVPrivateParameters; import org.bouncycastle.crypto.params.MQVPublicParameters; import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.Properties; public class ECMQVBasicAgreement implements BasicAgreement { MQVPrivateParameters privParams; public void init( CipherParameters key) { this.privParams = (MQVPrivateParameters)key; } public int getFieldSize() { return (privParams.getStaticPrivateKey().getParameters().getCurve().getFieldSize() + 7) / 8; } public BigInteger calculateAgreement(CipherParameters pubKey) { if (Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv")) { throw new IllegalStateException("ECMQV explicitly disabled"); } MQVPublicParameters pubParams = (MQVPublicParameters)pubKey; ECPrivateKeyParameters staticPrivateKey = privParams.getStaticPrivateKey(); ECDomainParameters parameters = staticPrivateKey.getParameters(); if (!parameters.equals(pubParams.getStaticPublicKey().getParameters())) { throw new IllegalStateException("ECMQV public key components have wrong domain parameters"); } ECPoint agreement = calculateMqvAgreement(parameters, staticPrivateKey, privParams.getEphemeralPrivateKey(), privParams.getEphemeralPublicKey(), pubParams.getStaticPublicKey(), pubParams.getEphemeralPublicKey()).normalize(); if (agreement.isInfinity()) { throw new IllegalStateException("Infinity is not a valid agreement value for MQV"); } return agreement.getAffineXCoord().toBigInteger(); } // The ECMQV Primitive as described in SEC-1, 3.4 private ECPoint calculateMqvAgreement( ECDomainParameters parameters, ECPrivateKeyParameters d1U, ECPrivateKeyParameters d2U, ECPublicKeyParameters Q2U, ECPublicKeyParameters Q1V, ECPublicKeyParameters Q2V) { BigInteger n = parameters.getN(); int e = (n.bitLength() + 1) / 2; BigInteger powE = ECConstants.ONE.shiftLeft(e); ECCurve curve = parameters.getCurve(); ECPoint[] points = new ECPoint[]{ // The Q2U public key is optional - but will be calculated for us if it wasn't present ECAlgorithms.importPoint(curve, Q2U.getQ()), ECAlgorithms.importPoint(curve, Q1V.getQ()), ECAlgorithms.importPoint(curve, Q2V.getQ()) }; curve.normalizeAll(points); ECPoint q2u = points[0], q1v = points[1], q2v = points[2]; BigInteger x = q2u.getAffineXCoord().toBigInteger(); BigInteger xBar = x.mod(powE); BigInteger Q2UBar = xBar.setBit(e); BigInteger s = d1U.getD().multiply(Q2UBar).add(d2U.getD()).mod(n); BigInteger xPrime = q2v.getAffineXCoord().toBigInteger(); BigInteger xPrimeBar = xPrime.mod(powE); BigInteger Q2VBar = xPrimeBar.setBit(e); BigInteger hs = parameters.getH().multiply(s).mod(n); return ECAlgorithms.sumOfTwoMultiplies( q1v, Q2VBar.multiply(hs).mod(n), q2v, hs); } }