Anyone have any additional thoughts on this?

I think the most significant item we need to discuss is the extent to which JCA should allow curve parameters for RFC 7748/8032 to be specified over the API. Does anyone know of a particular use case (that we haven't discuss already) that would require a provider to support arbitrary curves? Any other arguments for or against this feature?

On 8/7/2017 4:37 PM, Adam Petcher wrote:
I'm working on the Java implementation of RFC 7748 (Diffie-Hellman with X25519 and X448). I know some of you have been anxious to talk about how this would fit into JCA, and I appreciate your patience while I learned enough about JCA and existing crypto implementations to develop this API proposal. This API/design proposal is for RFC 7748 only, and it does not include the API for RFC 8032 (EdDSA). Of course, I expect many of the decisions that we make for RFC 7748 will also impact RFC 8032.

First off, I think it is important to separate RFC 7748 from the existing ECDH API and implementation. RFC 7748 is a different standard, it uses different encodings and algorithms, and it has different properties. Further, this separation will reduce the probability of programming errors (e.g. accidentally interpreting a Weierstrass point as an RFC 7748 point). So I propose that we use distinct algorithm names for RFC 7748, and that we don't use any of the existing EC classes like EllipticCurve and ECPoint with RFC 7748.

We can achieve this separation without duplicating a lot of code if we start with some simplifying assumptions. My goal is to remove functionality that nobody needs in order to simplify the design and API. If I am simplifying away something that you think you will need, please let me know.

A) We don't need to expose actual curve parameters over the API. Curves can be specified using names (e.g. "X25519") or OIDs. The underlying implementation will likely support arbitrary Montgomery curves, but the JCA application will only be able to use the supported named curves. B) We don't need direct interoperability between different providers using opaque key representations. We can communicate with other providers using X509/PKCS8 encoding, or by using KeyFactory and key specs.

These two assumptions greatly simplify the API. We won't need classes that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField, ECPublicKey, etc. for X25519/X448.

Now that the motivation and assumptions are out of the way, here is a description of the proposed JCA API:

1) The string "XDH" will be used in getInstance() to refer to all services related to RFC 7748 (KeyAgreement, KeyFactory, KeyPairGenerator, etc). This is a departure from the ECDH API that used "EC" for key generation (shared with ECDSA) and "ECDH" for KeyAgreement, and makes the RFC 7748 API more like "DiffieHellman" and other algorithms that use the same name for all services. 2) The new class (which implements AlgorithmParameterSpec) will be used to specify curves for RFC 7748. This class has a single String member which holds the name of the curve ("X25519" or "X448"). This parameter spec class can be reused by other crypto algorithms that similarly identify parameter sets using names (e.g. FFDHE3072 in DiffieHellman). This new class can be inserted into the hierarchy above ECGenParameterSpec. 3) There will be no classes in for EC public keys and private keys. An RFC 7748 implementation can use the existing classes X509EncodedKeySpec and PKCS8EncodedKeySpec for public and private key specs, respectively. 4) There will be no interfaces in for RFC 7748 public/private keys. Public/private key implementation classes will implement and, which allows access to their encoded representations.

Here is how the API will be implemented in the SunEC provider:

1) The public key and private key implementation classes will extend and, respectively. This is similar to ECPublicKeyImpl and ECPrivateKeyImpl. 2) The KeyFactory for RFC 7748 will support translation to/from opaque keys and X509EncodedKeySpec/PKCS8EncodedKeySpec.

Example code:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
kpg.initialize(paramSpec); // equivalent to kpg.initialize(255)
KeyPair kp = kpg.generateKeyPair();

KeyFactory kf = KeyFactory.getInstance("XDH");
X509EncodedKeySpec pubSpec = ...
PublicKey pubKey = kf.generatePublic(pubSpec);

KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();

One thing that is missing from the "core" API proposal is a way to easily produce a public/private key from an encoded numeric value. Of course, it's possible to put this value into a complete encoded X509/PKCS8 key, but that is not very convenient. Perhaps we can add another key spec class (that holds e.g. an AlgorithmParameterSpec and a byte array) to make this easier, but I don't know how valuable this would be.

I appreciate any feedback the experts on the mailing list may have for me. Please let me know what you think.

Reply via email to