On 8/8/2017 12:50 PM, Michael StJohns wrote:


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 is setting up a strawman and knocking it down. It's already possible to do the above with any software based key - either directly or by pulling out the data. Creating the API as you suggest will still not prevent this as long as I can retrieve the private value from the key.

If you want absolute protection from this - go to hardware based keys.

The goal is the prevention of common programming errors that lead to security issues, not absolute protection like you would get from hardware crypto. More like the kind of assurance you get from a type system.

<snip>


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?
Because names and OIDs get assigned later than the curve parameters. There are two parts to the JCA - the general crypto part and then there's the PKIX part. For the EC stuff, they sort of overlap because of a desire not to have to have everyone remember each of the parameter sets (curves) and those sets are tagged by name(s) and OID. But its still perfectly possible to do EC math on curves that were generated elsewhere (or even with a curve where everything but the basepoint is the same with a public curve).

What you need to be able to do is to pass to an "older" provider a "newer" curve - assuming the curve fits within the math already implemented. There's really no good reason to implement a whole new set of API changes just to permit a single new curve.

Okay, thanks. If I am reading this right, this feature supports interoperability with providers that don't know about a specific curve name/OID, but support all curves within some family. Without a way to express the curve parameters in JCA, you would resort to using some provider-specific parameter spec, which would be unfortunate.


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.

The common use case is much wider than you think it is. I find myself using the curve parameters much more than I would like - specifically because I use JCA in conjunction with PKCS11, HSMs and smart cards. So no - focusing on a software only subset of things is really not the right approach.

I actually would have expected hardware crypto to have *less* support for arbitrary curves, and so this issue would come up more with software implementations. Why does this come up so frequently in hardware?





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?

The method signatures for Signature.initSign(PrivateKey privateKey[,SecureRandom random]), Signature.initVerify(PublicKey publicKey) should give you a clue. E.g. the calls to the JCA provider classes require that you submit either a PublicKey or a PrivateKey. So you're going to need a concrete class with a subinterface that matches the key type needed by the signature instance that is a sub interface for PublicKey or PrivateKey.

Does my Signature service need to support a public subinterface of (for example) PublicKey? At a minimum, I need a concrete class that implements PublicKey. This class could be entirely internal to my provider. In Signature.initVerify(PublicKey), I can check whether the provided key is an instance of my internal concrete class, and fail otherwise. In this circumstance, my concrete key class doesn't need to implement any public subinterface of PublicKey.

The above arrangement basically works, but is it okay? Of course, objects of my concrete class could not be used by other providers, because they don't know how to interpret them. Is there some requirement or expectation of interoperability with other providers that I am missing?

Another option to consider is that we don't have subinterfaces for RFC 7748 public/private keys, but rather we use some common subinterface that provides enough information (e.g. the encoded number and the curve parameters).


KeyAgreement requires a "Key" (both the public and private keys are passed in a Key's).

KeyPairGenerator.init requires an AlgorithmParameter or a key size in bits.

KeyFactory requires a KeySpec.

Basically, you can't sign, perform a key agreement, generate a random key pair or generate a key from an encoded value without these classes.


It's scary that you asked this question because it implies perhaps a need to spend a bit more time looking at the JCA and how its structured.


Later, Mike


Reply via email to