Agreements are supported via the GordianAgreementFactory interface.
Algorithms are represented by GordianAgreementSpec. A GordianAgreement is obtained via the agreementSpec, and then agreements are created between the two parties depending on the type of the agreement and the resultType. The resultTypes can be any of the following
ResultType | Description |
---|---|
GordianParameters | The underlying agreement is used as the security phrase with the rest of the supplied parameters to generate a new personalised GordianFactory |
GordianKeySetSpec | The underlying agreement is used to generate a new GordianKeySet of the specified type, belonging to an agreed BC factory. |
GordianSymCipherSpec | The agreement is used to generate a new GordianSymCipher Key and InitVector (if required), belonging to an agreed BC factory. A pair of GordianSymCiphers are returned as the result, one for encryption and one for decryption |
GordianStreamCipherSpec | Similar to GordianSymKeySpec. |
null | The raw agreement bytes are returned. |
Agreements are always targeted by a Client towards a Server. The GordianAgreement that is created will implement an appropriate interface as per the following sections
GordianAnonymousAgreement is a oneShot process where the Client must already know the publicKey of the Server. It will generate a ClientHello message that is sent to the Server. The Server knows nothing about the Client. A random client InitVector is included in the message to randomise the result.
/* Access factory */ final GordianFactory myBaseFactory = GordianGenerator.createFactory(); final GordianKeyPairFactory myKeyPairFactory = myBase.getKeyPairFactory(); final GordianAgreementFactory myAgreementFactory = myKeyPairFactory.getAgreementFactory(); /* Access keyPairGenerator and create sending/receiving pairs */ final GordianKeyPairSpec mySpec = GordianKeyPairSpec.dh(GordianDHGroup.FFDHE2048); final GordianKeyPairGenerator myGenerator = myKeyPairFactory.getKeyPairGenerator(mySpec); final GordianKeyPair myClientPair = myGenerator.generateKeyPair(); final GordianKeyPair myServerPair = myGenerator.generateKeyPair(); /* Create anonymous agreement */ final GordianAgreementSpec myAgreeSpec = GordianAgreementSpec.anon(mySpec, GordianKDFType.SHA256KDF); final GordianSymCipherSpec myCipherSpec = GordianSymCipherSpec.cbc(GordianGordianSymKeySpec.aes(GordianLength.LEN_256), GordianPadding.PKCS7); final GordianAnonymousAgreement myAnonClient = (GordianAnonymousAgreement) myAgreementFactory.createAgreement(myAgreeSpec); final GordianAnonymousAgreement myAnonServer = (GordianAnonymousAgreement) myAgreementFactory.createAgreement(myAgreeSpec); /* Client side */ myAnonClient.setResultType(myCipherSpec); final byte[] myClientHello = myAnonClient.createClientHello(myServerPair); final GordianSymCipher[] myClientCiphers = (GordianSymCipher[]) myAnonClient.getResult(); /* Send myClientHello to server */ /* Server side */ myAnonServer.acceptClientHello(myServerPair, myClientHello); final GordianSymCipherSpec myResultCipherSpec = (GordianSymCipherSpec) myAnonServer.getResultType(); final GordianSymCipher[] myServerCiphers = (GordianSymCipher[]) myAnonServer.getResult();
GordianHandshakeAgreement requires the Client to generate a ClientHello message that is sent to the Server. The Server will process the ClientHello and generate a ServerHello message in response which is returned to the Client. Generally both parties should know the publicKey of the partner, and it is expected that the user would pass the certificates for the publicKeys along with the ClientHello and ServerHello messages. A random client InitVector is included in the ClientHello message and a random server InitVector in the ServerHello message to randomise the result.
Confirmation can also be required by the agreementSpec. In this case the Client will send an additional ClientConfirm message to the Server after processing the ServerHello message. The Server can determine that a confirmation is due either by checking the agreementSpec or by checking the status of the agreement. The SM2 confirm is defined by the SM2 algorithm. For UNIFIED and MQV agreements the confirmation tags are calculated over the well-known and ephemeral keyPairs using an hMac keyed by the agreed result.
/* Access factory */ final GordianFactory myBaseFactory = GordianGenerator.createFactory(); final GordianKeyPairFactory myKeyPairFactory = myBase.getKeyPairFactory(); final GordianAgreementFactory myAgreementFactory = myKeyPairFactory.getAgreementFactory(); /* Access keyPairGenerator and create sending/receiving pairs */ final GordianKeyPairSpec mySpec = GordianKeyPairSpec.dh(GordianDHGroup.FFDHE2048); final GordianKeyPairGenerator myGenerator = myKeyPairFactory.getKeyPairGenerator(mySpec); final GordianKeyPair myClientPair = myGenerator.generateKeyPair(); final GordianKeyPair myServerPair = myGenerator.generateKeyPair(); /* Create handshake agreement */ final GordianAgreementSpec myAgreeSpec = GordianAgreementSpec.unified(mySpec, GordianKDFType.SHA256KDF); final GordianKeySetSpec myKeySetSpec = new GordianKeySetSpec(GordianLength.LEN_256); final GordianHandshakeAgreement myHandshakeClient = (GordianHandshakeAgreement) myAgreementFactory.createAgreement(myAgreeSpec); final GordianHandshakeAgreement myHandshakeServer = (GordianHandshakeAgreement) myAgreementFactory.createAgreement(myAgreeSpec); /* Client side */ myHandshakeClient.setResultType(myKeySetSpec); final byte[] myClientHello = myHandshakeClient.createClientHello(myClientPair); /* Send myClientHello (plus Client Certificate) to server */ /* Server side */ final byte[] myServerHello = myHandshakeServer.acceptClientHello(myClientPair, myServerPair, myClientHello); if (myHandshakeServer.getStatus() == GordianAgreementStatus.RESULT_AVAILABLE) { /* Can access result now without waiting for confirmation */ } /* Send myServerHello (plus Server Certificate) to server */ /* Client side */ final byte[] myClientConfirm = myHandshakeClient.acceptServerHello(myServerPair, myServerHello); final GordianKeySet myClientKeySet = (GordianKeySet) myHandshakeClient.getResult(); /* If we are performing a confirm */ if (myClientConfirm != null) { /* Send myClientConfirm to server */ /* Server side */ myHandshakeServer.processClientConfirm(myClientConfirm); } /* Server side */ final GordianKeySetSpec myResultKeySetSpec = (GordianKeySetSpec) myHandshakeServer.getResultType(); final GordianKeySet myServerKeySet = (GordianKeySet) myHandshakeServer.getResult();
GordianSignedAgreement works similarly to the Handshake agreement without the confirmation message. The difference is that the keys used in the agreement are ephemeral and the only well-known key is the publicKey of the server which is used to authenticate the ServerHello message. A pair of random InitVectors are included in the messages as per the handshake agreement to randomise the result.
The signature is calculated over the two ephemeral keys and the initVectors
/* Access factory */ final GordianFactory myBaseFactory = GordianGenerator.createFactory(); final GordianKeyPairFactory myKeyPairFactory = myBase.getKeyPairFactory(); final GordianAgreementFactory myAgreementFactory = myKeyPairFactory.getAgreementFactory(); /* Access keyPairGenerator and create server pair */ final GordianKeyPairSpec mySpec = GordianKeyPairSpec.ed448(); final GordianKeyPairGenerator myGenerator = myKeyPairFactory.getKeyPairGenerator(mySpec); final GordianKeyPair myServerPair = myGenerator.generateKeyPair(); /* Create signed agreement */ final GordianAgreementSpec myAgreeSpec = GordianAgreementSpec.signed(mySpec, GordianKDFType.SHA256KDF); final GordianKeySetSpec myKeySetSpec = new GordianKeySetSpec(GordianLength.LEN_256); final GordianSignedAgreement myHandshakeClient = (GordianSignedAgreement) myAgreementFactory.createAgreement(myAgreeSpec); final GordianSignedAgreement myHandshakeServer = (GordianSignedAgreement) myAgreementFactory.createAgreement(myAgreeSpec); /* Client side */ myHandshakeClient.setResultType(myKeySetSpec); final byte[] myClientHello = myHandshakeClient.createClientHello(GordianAsymKeySpec.dh(GordianDHGroup.rfc7919_ffdhe2048)); /* Send myClientHello (plus Client Certificate) to server */ /* Server side */ final byte[] myServerHello = myHandshakeServer.acceptClientHello(myServerPair, myClientHello); final GordianKeySetSpec myResultKeySetSpec = (GordianKeySetSpec) myHandshakeServer.getResultType(); final GordianKeySet myServerKeySet = (GordianKeySet) myHandshakeServer.getResult(); /* Send myServerHello (plus Server Certificate) to server */ /* Client side */ myHandshakeClient.acceptServerHello(myServerPair, myServerHello); final GordianKeySet myClientKeySet = (GordianKeySet) myHandshakeClient.getResult();
In all the above examples the server supports a single GordianAgreementSpec. In reality it might support a number of different specs. It can obtain the required GordianAgreementSpec from the ClientHello and switch strategies accordingly. It can also interrogate the KeyPairType should it support multiple keyPairs.
/* Access factory */ final GordianFactory myBaseFactory = GordianGenerator.createFactory(); final GordianKeyPairFactory myKeyPairFactory = myBase.getKeyPairFactory(); final GordianAgreementFactory myAgreementFactory = myKeyPairFactory.getAgreementFactory(); /* Access clientHello and determine the agreementSpec that it represents */ final byte[] myClientHello = ..... final GordianAgreement myAgreement = myAgreementFactory.createAgreement(myClientHello); if (myAgreement instanceof GordianAnonymousAgreement) { .... } else if (myAgreement instanceof GordianHandshakeAgreement) { .... } else if (myAgreement instanceof GordianSignedAgreement) { .... }
Composite agreements may be created by a composite keyPair, as long as each element of the composite keyPair is capable of supporting the desired AgreementSpec. There are two small variations.
/* Access factory */ final GordianFactory myBaseFactory = GordianGenerator.createFactory(); final GordianKeyPairFactory myKeyPairFactory = myBase.getKeyPairFactory(); final GordianAgreementFactory myAgreementFactory = myKeyPairFactory.getAgreementFactory(); /* Access keyPairGenerator */ final GordianKeyPairSpec mySpec = GordianKeyPairSpec.composite(GordianKeyPairSpec.dh(GordianDGroup.FFDHE2048), GordianKeyPairSpec.ec(GordianDSAElliptic.SECP256R1)); final GordianKeyPairGenerator myGenerator = myKeyPairFactory.getKeyPairGenerator(mySpec); final GordianKeyPair myKeyPair = myGenerator.generateKeyPair(); GordianKeyPair mySigningPair = myKeyPair; /* Access agreement */ final GordianAgreementSpec myAgreeSpec = GordianAgreementSpec.composite(mySpec, GordianKDFType.SHA256KDF); final GordianAgreement myAgree = myAgreementFactory.createAgreement(myAgreeSpec); /* Handle as standard */ ....
The following agreement algorithms are supported.
Algorithm | Type | KeyTypes | Notes |
---|---|---|---|
KEM | Anonymous | RSA, EC, GOST2012, DSTU4145, SM2, CMCE, Frodo, SABER KYBER, BIKE, HQC, NTRU, NTRUPRIME | RSA, EC, GOST2012, DSTU4145 and SM2 are not available on JCA |
Anonymous | Anonymous | DH, EC, GOST2012, DSTU4145, SM2, XDH | |
Basic | Handshake | DH, EC, GOST2012, DSTU4145, SM2, XDH | |
Signed | Signed | DH, EC, GOST2012, DSTU4145, SM2, XDH | |
MQV | Handshake | DH, EC, GOST2012, DSTU4145, SM2 | |
Unified | Handshake | DH, EC, GOST2012, DSTU4145, SM2, XDH | |
SM2 | Handshake | EC, GOST2012, SM2 | Not available on JCA |