Skip to content

Commit

Permalink
multi-part EC CDH.
Browse files Browse the repository at this point in the history
  • Loading branch information
dghgit committed Mar 29, 2020
1 parent c1bd763 commit c96c8d4
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.bouncycastle.crypto;

import org.bouncycastle.crypto.params.AsymmetricKeyParameter;

public interface StagedAgreement
extends BasicAgreement
{
AsymmetricKeyParameter calculateStage(CipherParameters pubKey);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.bouncycastle.crypto.agreement;

import java.math.BigInteger;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.StagedAgreement;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECPoint;

public class ECDHCStagedAgreement
implements StagedAgreement
{
ECPrivateKeyParameters key;

public void init(
CipherParameters key)
{
this.key = (ECPrivateKeyParameters)key;
}

public int getFieldSize()
{
return (key.getParameters().getCurve().getFieldSize() + 7) / 8;
}

public AsymmetricKeyParameter calculateStage(
CipherParameters pubKey)
{
ECPoint P = calculateNextPoint((ECPublicKeyParameters)pubKey);

return new ECPublicKeyParameters(P, key.getParameters());
}

public BigInteger calculateAgreement(
CipherParameters pubKey)
{
ECPoint P = calculateNextPoint((ECPublicKeyParameters)pubKey);

return P.getAffineXCoord().toBigInteger();
}

private ECPoint calculateNextPoint(ECPublicKeyParameters pubKey)
{
ECPublicKeyParameters pub = pubKey;
ECDomainParameters params = key.getParameters();
if (!params.equals(pub.getParameters()))
{
throw new IllegalStateException("ECDHC public key has wrong domain parameters");
}

BigInteger hd = params.getH().multiply(key.getD()).mod(params.getN());

// Always perform calculations on the exact curve specified by our private key's parameters
ECPoint pubPoint = ECAlgorithms.cleanPoint(params.getCurve(), pub.getQ());
if (pubPoint.isInfinity())
{
throw new IllegalStateException("Infinity is not a valid public key for ECDHC");
}

ECPoint P = pubPoint.multiply(hd).normalize();

if (P.isInfinity())
{
throw new IllegalStateException("Infinity is not a valid agreement value for ECDHC");
}

return P;
}
}
46 changes: 46 additions & 0 deletions core/src/test/java/org/bouncycastle/crypto/test/ECTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.BasicAgreement;
import org.bouncycastle.crypto.StagedAgreement;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
import org.bouncycastle.crypto.agreement.ECDHCStagedAgreement;
import org.bouncycastle.crypto.agreement.ECDHCUnifiedAgreement;
import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECDHUPrivateParameters;
import org.bouncycastle.crypto.params.ECDHUPublicParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
Expand Down Expand Up @@ -825,6 +828,47 @@ private void testECDHBasicAgreementCofactor()
}
}

private void testECDHStagedAgreement()
{
SecureRandom random = new SecureRandom();

X9ECParameters x9 = CustomNamedCurves.getByName("curve25519");
ECDomainParameters ec = new ECDomainParameters(x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());

ECKeyPairGenerator kpg = new ECKeyPairGenerator();
kpg.init(new ECKeyGenerationParameters(ec, random));

AsymmetricCipherKeyPair p1 = kpg.generateKeyPair();
AsymmetricCipherKeyPair p2 = kpg.generateKeyPair();
AsymmetricCipherKeyPair p3 = kpg.generateKeyPair();

StagedAgreement e1 = new ECDHCStagedAgreement();
StagedAgreement e2 = new ECDHCStagedAgreement();
StagedAgreement e3 = new ECDHCStagedAgreement();

e1.init(p1.getPrivate());
e2.init(p2.getPrivate());
e3.init(p3.getPrivate());

AsymmetricKeyParameter stage1_12 = e1.calculateStage(p2.getPublic());
AsymmetricKeyParameter stage1_23 = e2.calculateStage(p3.getPublic());
AsymmetricKeyParameter stage1_31 = e3.calculateStage(p1.getPublic());

BigInteger k1 = e1.calculateAgreement(stage1_23);
BigInteger k2 = e2.calculateAgreement(stage1_31);
BigInteger k3 = e3.calculateAgreement(stage1_12);

if (!k1.equals(k2))
{
fail("1-2 calculated agreement test failed");
}

if (!k3.equals(k2))
{
fail("3-2 calculated agreement test failed");
}
}

private void testECMQVTestVector1()
{
// Test Vector from GEC-2
Expand Down Expand Up @@ -1125,6 +1169,8 @@ public void performTest()

testECUnifiedTestVector1();
testECUnifiedTestVector2();

testECDHStagedAgreement();
}


Expand Down

0 comments on commit c96c8d4

Please sign in to comment.