18212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrompackage org.bouncycastle.crypto.agreement;
28212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
38212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport java.math.BigInteger;
48212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
58212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport org.bouncycastle.crypto.BasicAgreement;
68212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport org.bouncycastle.crypto.CipherParameters;
78212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport org.bouncycastle.crypto.params.ECPrivateKeyParameters;
870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.crypto.params.ECPublicKeyParameters;
9f81961d489888391053b9d69720fa47714685509Quan Nguyen// BEGIN android-added
10f81961d489888391053b9d69720fa47714685509Quan Nguyenimport org.bouncycastle.math.ec.ECCurve;
11f81961d489888391053b9d69720fa47714685509Quan Nguyen// END android-added
1270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.math.ec.ECPoint;
138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom/**
158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * P1363 7.2.1 ECSVDP-DH
168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom *
178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * and [Kob87]. This primitive derives a shared secret value from one
208212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * party's private key and another party's public key, where both have
218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * the same set of EC domain parameters. If two parties correctly
228212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * execute this primitive, they will produce the same output. This
238212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * primitive can be invoked by a scheme to derive a shared secret key;
248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * specifically, it may be used with the schemes ECKAS-DH1 and
258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * Section 7.2.2).
278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom */
288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrompublic class ECDHBasicAgreement
298212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    implements BasicAgreement
308212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom{
318212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    private ECPrivateKeyParameters key;
328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
338212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public void init(
348212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        CipherParameters key)
358212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
368212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        this.key = (ECPrivateKeyParameters)key;
378212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
388212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
3970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    public int getFieldSize()
4070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
4170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return (key.getParameters().getCurve().getFieldSize() + 7) / 8;
4270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
4370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
448212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public BigInteger calculateAgreement(
458212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        CipherParameters pubKey)
468212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
47f81961d489888391053b9d69720fa47714685509Quan Nguyen        // BEGIN android-changed
48f81961d489888391053b9d69720fa47714685509Quan Nguyen        ECPoint peerPoint = ((ECPublicKeyParameters) pubKey).getQ();
49f81961d489888391053b9d69720fa47714685509Quan Nguyen        ECCurve myCurve = key.getParameters().getCurve();
50f81961d489888391053b9d69720fa47714685509Quan Nguyen        if (peerPoint.isInfinity()) {
51f81961d489888391053b9d69720fa47714685509Quan Nguyen          throw new IllegalStateException("Infinity is not a valid public key for ECDH");
52f81961d489888391053b9d69720fa47714685509Quan Nguyen        }
53f81961d489888391053b9d69720fa47714685509Quan Nguyen        try {
54f81961d489888391053b9d69720fa47714685509Quan Nguyen          myCurve.validatePoint(peerPoint.getXCoord().toBigInteger(),
55f81961d489888391053b9d69720fa47714685509Quan Nguyen              peerPoint.getYCoord().toBigInteger());
56f81961d489888391053b9d69720fa47714685509Quan Nguyen        } catch (IllegalArgumentException ex) {
57f81961d489888391053b9d69720fa47714685509Quan Nguyen          throw new IllegalStateException("The peer public key must be on the curve for ECDH");
58f81961d489888391053b9d69720fa47714685509Quan Nguyen        }
59f81961d489888391053b9d69720fa47714685509Quan Nguyen        // Explicitly construct a public key using the private key's curve.
60f81961d489888391053b9d69720fa47714685509Quan Nguyen        ECPoint pubPoint = myCurve.createPoint(peerPoint.getXCoord().toBigInteger(),
61f81961d489888391053b9d69720fa47714685509Quan Nguyen            peerPoint.getYCoord().toBigInteger());
6216f9ee464b68937f45d009d9c1b0eb9b544a8deeSergio Giro        ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
634caba4cfca3316673ae4e330e8a47932bed8a53aSergio Giro        if (!pub.getParameters().equals(key.getParameters()))
644caba4cfca3316673ae4e330e8a47932bed8a53aSergio Giro        {
654caba4cfca3316673ae4e330e8a47932bed8a53aSergio Giro            throw new IllegalStateException("ECDH public key has wrong domain parameters");
664caba4cfca3316673ae4e330e8a47932bed8a53aSergio Giro        }
67f81961d489888391053b9d69720fa47714685509Quan Nguyen        ECPoint P = pubPoint.multiply(key.getD()).normalize();
68f81961d489888391053b9d69720fa47714685509Quan Nguyen        // END android-changed
698212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
705db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (P.isInfinity())
715db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            throw new IllegalStateException("Infinity is not a valid agreement value for ECDH");
735db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
748212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return P.getAffineXCoord().toBigInteger();
768212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
778212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom}
78