JCA design for RFC 7748

Adam Petcher adam.petcher at oracle.com
Tue Aug 8 15:25:15 UTC 2017


Thanks for the feedback. See below for my responses.

On 8/7/2017 5:52 PM, Michael StJohns wrote:
> 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).
>
> So you're expecting yet another set of APIs to cover those as well? 
> Rather than one API to cover all of the new curves?  Seems to be a bit 
> short sighted.

I'm expecting that we don't need to expose curve parameters/points in 
the API, so we won't need any new API for EdDSA, other than the 
algorithm name. If we decide we need to expose curve parameters, then we 
may want to back up and consider how EdDSA fits into this.

>
>> 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's still an elliptic curve.  Note that there is already a worked 
> example here - F2m vs Fp curves.
>
>> it uses different encodings and algorithms,
>
> From a JCA point of view, the public key gets encoded as an 
> SubjectPublicKeyInfo and the private key gets encoded as a PKCS8 - 
> that's for lots and lots of compatibility reasons.  The public point 
> of the public key might be encoded (inside the SPKI) as little endian 
> OCTET STRING array vs a  big endian ASN1 INTEGER, but its still just 
> an integer internally.
>
> The algorithms are Key Agreement and Signature - those are at least 
> what JCA will see them as.  The actual 
> KeyAgreement.getInstance("name") is of course going to be different 
> than KeyAgreement.getInstance("ECDH") for example.
>
>
>> and it has different properties.
>
> Details please?  Or do you mean that you can't use a given type of key 
> for both key agreement and signature?

Specifically, RFC 7748 resists (some) side-channel attacks and 
invalid-point attacks. The "ECDH" algorithm in JCA (PKCS#3) does not 
have these properties, so I want to make sure programmers don't get them 
confused. This difference in security properties partially motivates the 
use of a new algorithm name, rather than reusing "ECDH" for RFC 7748.

>
>> Further, this separation will reduce the probability of programming 
>> errors (e.g. accidentally interpreting a Weierstrass point as an RFC 
>> 7748 point).
>
> Um.  What?   It actually won't.

This is the sort of problem I want to avoid:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
KeyPair kp = kpg.generateKeyPair();
KeyFactory eckf = KeyFactory.getInstance("ECDH");
ECPrivateKeySpec priSpec = eckf.getKeySpec(kf.getPrivate(), 
ECPrivateKeySpec.class);

KeyFactory xdhkf = KeyFactory.getInstance("XDH");
PrivateKey xdhPrivate = xdhkf.generatePrivate(priSpec);

// Now use xdhPrivate for key agreement, which uses the wrong algorithm 
and curve, and may leak information about the private key

This sort of thing can happen if we use the existing EC spec classes for 
RFC 7748 (e.g. redefining what "a" and "b" mean in EllipticCurve when 
used with a Montgomery curve, leaving "y" null in ECPoint). Of course, 
we can prevent it by tagging these objects and checking the tags to make 
sure they are used with the correct algorithms, but I would prefer to 
use separate classes (if necessary) and let the type checker do this.

My intention is that errors like the one above are impossible in my 
proposed design. We should be able to accomplish this by only using 
encoded key specs (which already have checking based on OID), or by 
using new classes, if this is necessary (and I hope it is not).

>
>> So I propose that we use distinct algorithm names for RFC 7748,
> Yes.
>
>> and that we don't use any of the existing EC classes like 
>> EllipticCurve and ECPoint with RFC 7748.
> No.   (My opinion but...) It's *hard* to add new meta classes for 
> keys.  Just considering the EC stuff you have ECKey, ECPublicKey, 
> ECPrivateKey, EllipticCurve, ECPublicKeySpec, ECPrivateKeySpec, 
> ECPoint, ECParameterSpec, ECGenParameterSpec, EllipticCurve and 
> ECField (with ECFieldF2M and ECFieldF2P being the differentiator for 
> all of the various keys within this space).
>
>>
>> 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.
>
> There's a difference with what you do with the public API vs what you 
> do with the plugin provider.    Throwing away all of the 
> "functionality that nobody needs" will probably come back to bite 
> those who come later with something that looks *almost* like what you 
> did, but needs just one more parameter than you were kind enough to 
> leave behind.

I agree, but we have to draw the line somewhere, and I think that line 
should be determined by the most common use cases. I would prefer to put 
in too little, and add more to the API later when people ask for it. 
Adding things to the API isn't trivial, but it is much easier than 
removing things that we don't need that are complicating the API and 
causing problems.

>
>>
>> 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.
>
> Strangely, this hasn't turned out all that well.  There needs to be a 
> name, OID in the public space (primarily for the encodings and PKIX 
> stuff) and to be honest - you really want the parameters in public 
> space as well (the ECParameterSpec and its ilk) so that a given key 
> can be used with different providers or even to play around internally 
> with new curves before giving them a name.

I don't understand why we need public curve parameters to allow keys to 
be used with different providers. It seems like this should work as long 
as the providers all understand the OIDs or curve names. Can you explain 
this part a bit more?

Related to tinkering with new curves that don't have a name: I don't 
think that this is a feature that JCA needs to have. In the common use 
case, the programmer wants to only use standard algorithms and curves, 
and I think we should focus on that use case.

>
>> 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.
> I don't actually understand that statement.  Keys of different 
> providers generally don't interoperate anyways, but you can mostly 
> take an "encoded" one and create a new one in a new provider via the 
> Keyfactory.  KeySpecs provide you with a way of manually building a 
> key - and that turns out to be VERY necessary, especially when you're 
> dealing with adapting hardware modules to the JCA.

I'll admit that it is a strange statement. The only reason why I stated 
this assumption is that ECPublicKey and ECPrivateKey expose a lot of 
information that allows direct interoperability with opaque key objects 
(that implement these interfaces). I don't know if this is 
necessary/valuable, and I don't have any particular desire to allow the 
same thing with RFC 7748 keys.

>
>>
>> These two assumptions greatly simplify the API. We won't need classes 
>> that mirror ECParameterSpec, EllipticCurve, ECPoint, ECField, 
>> ECPublicKey, etc. for X25519/X448.
>
> That assumption holds only if your various other assumptions hold. My 
> opinion is that they probably don't.  (BTW - I'm pretty sure, given 
> that every single asymmetric JCA crypto api takes a PublicKey or 
> PrivateKey you're going to need to mirror those classes at least; 
> you'll also need a ParameterSpec and a GenParameterSpec class with 
> whatever underlying supporting classes are required to deal with 
> KeyFactory's)

I agree with the second part of your parenthetical statement, but I need 
more information about the first. It sounds like what you are saying is 
that I will need something like XDHPublicKey and XDHPrivateKey in 
java.security.interfaces. Can you tell me why? What is it that we can't 
do without these interfaces?

>
>>
>> Now that the motivation and assumptions are out of the way, here is a 
>> description of the proposed JCA API:
>
> I'd suggest getting agreement on the above before proceeding.
>
> Later, Mike
>




More information about the security-dev mailing list