Re: JCA design for RFC 7748
On 8/10/2017 6:46 PM, Michael StJohns wrote: On 8/10/2017 7:36 PM, Xuelei Fan wrote: Hi Michael, Good points! See comments inlines. On 8/10/2017 3:20 PM, Michael StJohns wrote: Instead of converting, I was thinking about mapping. E.g. Montgomery A and B matches the A and B of the curve. But the "x" of the Montgomery point is just the "x" of the ECPoint with the "y" left as null. For Edwards, it looks like you would map "d" to A. For [3] I'd map "r" to A. I'd leave B as null for both- no reason to throw an unsupported exception as the code generally has a clue about what types of keys they're dealing with (or we provide a marker so they can figure it out). The conversion in and out for points is a conversion from little endian to big endian and vice versa, but that only has to be done if you're importing or exporting a parameter set and that's an implementation issue not an API issue. Basically, all the math is BigIntegers under the hood. The curve25519 RFC specifies an implementation that's little endian, but the actual math is just math and things like the public key is really just a BigInteger. Old code would just continue to work - since it would not be using the new curves. New code would have to look for the curve type marker (e.g. the ECField) if there was the possibility of confusion. I understand your points. The mapping may be confusing to application developers, but no problem for new codes if following the new coding guideline. I'm not very sure of the old code, for similar reason to use the converting solution. For example, an Edwards curve form of the SubjectPublicKeyInfo field in a X.509 cert is parsed as X509EncodedKeySpec, and "EC" KeyFactory is used to generate the ECPublicKey. The algorithm name of the ECPublicKey instance is "EC", and the parameter is an instance of ECParameterSpec. Somehow, the ECPublicKey leave the key generation environment, and the curve OID is unknown in the new environment. Then the public could be used improperly. In the past, it's fine as the only supported form is Weierstrass form, there is no need to tell the curve forms in a crypto implementation. However, when a new form is introduces, identify the EC form of a key is an essential part for the following crypto operations. Old providers or codes may not be able to tell the form, as may result in compatibility issues. I don't think any of this is an issue. An X509EncodedKeySpec for either type of key has a id-ecPublicKey OID identifying it (embedded in the SubjectPublicKeyInfo encoding). In the key body, there's the EcpkParameters structure which is a 'namedCurve' which consists of an OID. The curve OIDs for 25519 and 447 are different than any of the Weiserstrass keys. When the KeyFactory factory implementation reads the byte stream its going to build a JCA ECPublicKey that matches the OID AND that's a concrete ECPublicKey class of the key factory provider. If the factory implementation doesn't understand the oid, then the provider throws an error. I forget which one. > The concrete class for the ECPublic key is specific to the provider. Some providers may support the new key forms, some may not. There's no guarantee (and there never has been a guarantee) that an ECPublic key from one provider can be used with another provider (e.g. PKCS11 provider vs a software provider) - you have to convert the key into a keyspec and then run the factory method on it. I'm not sure of it. JDK is a multiple providers framework. A key generated in one provider may work in another provider, as if the conversion of the key works. It's not rare that the public key is parsed by one provider, and used in another provider. For some cases, we don't have conversion problem in the past as the key spec is clear. But for some other cases, we do have problems. But if a case works in the past, we don't want to break it; otherwise, it might be a kind of compatibility issues. As we discussed, there are multiple forms of EC curves. EC curves form is an essential part of a EC key for following operation. As if the EC curves form is unknown, there are potential problems. When a old provider try to use a new provider generated keys for a new forms, problems happens. This actually can be avoid if the old provider does not support this algorithm. The "EC" name is too general to accept new forms. So I don't think there's anything we have to worry about here - no violation of the API contract as far as I can tell. (As a more complete example - consider what happens when you have an F2M EC provider and an Fp EC provider both generating public keys and encoding them. Neither provider can decode the other's encoded key because they don't have the OIDs and the parameter sets). If we define all of the forms at the same time, a provider would follow the specs, and no compatibility issues. However, if we add something new later, and
Re: JCA design for RFC 7748
On 8/10/2017 7:36 PM, Xuelei Fan wrote: Hi Michael, Good points! See comments inlines. On 8/10/2017 3:20 PM, Michael StJohns wrote: Instead of converting, I was thinking about mapping. E.g. Montgomery A and B matches the A and B of the curve. But the "x" of the Montgomery point is just the "x" of the ECPoint with the "y" left as null. For Edwards, it looks like you would map "d" to A. For [3] I'd map "r" to A. I'd leave B as null for both- no reason to throw an unsupported exception as the code generally has a clue about what types of keys they're dealing with (or we provide a marker so they can figure it out). The conversion in and out for points is a conversion from little endian to big endian and vice versa, but that only has to be done if you're importing or exporting a parameter set and that's an implementation issue not an API issue. Basically, all the math is BigIntegers under the hood. The curve25519 RFC specifies an implementation that's little endian, but the actual math is just math and things like the public key is really just a BigInteger. Old code would just continue to work - since it would not be using the new curves. New code would have to look for the curve type marker (e.g. the ECField) if there was the possibility of confusion. I understand your points. The mapping may be confusing to application developers, but no problem for new codes if following the new coding guideline. I'm not very sure of the old code, for similar reason to use the converting solution. For example, an Edwards curve form of the SubjectPublicKeyInfo field in a X.509 cert is parsed as X509EncodedKeySpec, and "EC" KeyFactory is used to generate the ECPublicKey. The algorithm name of the ECPublicKey instance is "EC", and the parameter is an instance of ECParameterSpec. Somehow, the ECPublicKey leave the key generation environment, and the curve OID is unknown in the new environment. Then the public could be used improperly. In the past, it's fine as the only supported form is Weierstrass form, there is no need to tell the curve forms in a crypto implementation. However, when a new form is introduces, identify the EC form of a key is an essential part for the following crypto operations. Old providers or codes may not be able to tell the form, as may result in compatibility issues. I don't think any of this is an issue. An X509EncodedKeySpec for either type of key has a id-ecPublicKey OID identifying it (embedded in the SubjectPublicKeyInfo encoding). In the key body, there's the EcpkParameters structure which is a 'namedCurve' which consists of an OID. The curve OIDs for 25519 and 447 are different than any of the Weiserstrass keys. When the KeyFactory factory implementation reads the byte stream its going to build a JCA ECPublicKey that matches the OID AND that's a concrete ECPublicKey class of the key factory provider. If the factory implementation doesn't understand the oid, then the provider throws an error. I forget which one. The concrete class for the ECPublic key is specific to the provider. Some providers may support the new key forms, some may not. There's no guarantee (and there never has been a guarantee) that an ECPublic key from one provider can be used with another provider (e.g. PKCS11 provider vs a software provider) - you have to convert the key into a keyspec and then run the factory method on it. So I don't think there's anything we have to worry about here - no violation of the API contract as far as I can tell. (As a more complete example - consider what happens when you have an F2M EC provider and an Fp EC provider both generating public keys and encoding them. Neither provider can decode the other's encoded key because they don't have the OIDs and the parameter sets). However, I'm not very sure of the compatibility impact (see above). 3. Where we are not now? Using named curves is popular. There is a ECGenParameterSpec class using named curves: ECGenParameterSpec ecgp = new ECGenParameterSpec(secp256r1); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); kpg.initialize(ecpg); KeyPair kp = kpg.generateKeyPair(); ECPublicKey pubKey = (ECPublicKey)kp.getPublic(); String keyAlgorithm = pubKey.getAlgorithm(); // "EC" However, it is used for key generation only. Once the keys are generated, there is no public API to know the name of the curve in ECKey. ECKey.getAlgorithm() will return "EC" only. If it is required to known whether a key is of a named curve, the solution is not straightforward. This ties back to "getEncoded()" representations. Under the hood, if you do a getEncoded() there's a "which name does this parameter set match up to" search which checks various tables for an OID and uses that in an X.509 SPKI output object. On input, the table lookup has to see whether or not it understands the curve OID (or the key type
Re: CSR Review for 8159544: Remove deprecated classes in com.sun.security.auth.**
Done. Thanks Max > On Aug 10, 2017, at 11:36 PM, Sean Mullanwrote: > > On 8/9/17 8:02 PM, Weijun Wang wrote: >> Looks fine. Should the specification part be formatted with and fixed >> fonts? > > Fixed. Can you add your name as Reviewer (you need to edit the CSR and add > your name to the "Reviewed By" box). > > Thanks, > Sean > >> Thanks >> Max >>> On Aug 10, 2017, at 3:15 AM, Sean Mullan wrote: >>> >>> Max, >>> >>> Could you please review the following CSR: >>> >>> https://bugs.openjdk.java.net/browse/JDK-8186047 >>> >>> Thanks, >>> Sean
Re: JCA design for RFC 7748
Hi Michael, Good points! See comments inlines. On 8/10/2017 3:20 PM, Michael StJohns wrote: Hi Xuelei - Great analysis. Some comments in line. On 8/10/2017 3:10 PM, Xuelei Fan wrote: Hi, I want to extend the comment a little bit. 1. The background A elliptic curve is determined by either an equation of form y^2 = x^3 + ax + b(1) [Weierstrass form] or y^2 + xy = x^3 + ax^2 + b.(2) However, some other forms may also be used. For example: y^2 = x(x-1)(x-r) (3) or By^2 = x^3 + Ax^2 + x (4) [RFC 7748, Montgomery curve] x^2 + y^2 = 1 + dx^2y^2 (5) [RFC 7748, Edwards curve] In general, any elliptic curve can be written in Weierstrass form (1) or (2). That's, Montgomery curve and Edwards curve can be expressed in Weierstrass form. 2. Where we are now? In JDK, an elliptic curve is defined in the Weierstrass form ((1)/(2)). See java.security.spec.EllipticCurve: EllipticCurve(ECField field, BigInteger a, BigInteger b) In theory, the existing APIs can be used for RFC 7748, by converting the Montgomery curve and Edwards curve to the Weierstrass form. However, the conversion can be misleading and complicate the implementation significantly. For example, before using a point Weierstrass form (x, y), the implementation need to convert it to Montgomery curve (x', -) so as to use the fully potential of RFC 7748. The curves returned in public APIs need to use (x, y), while the implementation need to use (x', y'). It's very confusing and the compatibility impact could be significant. For example: public something(ECPublicKey ecPublicKey) { // Problem: If no other information, it is unclear // whether the ecPublicKey can be used for a particular // signature verification or not when the RFC 7748/8032 // get supported. // Problem: an old application may use ecPublicKey for // the old style operation, even the ecPublicKey is supposed // to be x25519. It's not easy to control the behavior in // legacy application code, and may introduce unexpected // security issues. } public KeyAgreement getKeyAgreement(AlgorithmParameterSpec aps) { // Problem: the code bellow should be comment in the current // code. However, the ECParameterSpec may not be able to use // for the old style "EC" key agreement. // // JDK crypto provider can take special action to avoid this // issue in the JCA/JCE implementation. But it cannot be // granted other provider can do this as well, and old // provider may run into problems as well. if (aps instance of ECParameterSpec) { return KeyAgreement.getInstance("EC"); } } What's the problem with ECPublicKey/ECPrivateKey/ECKey? It's mainly about the ECParameterSpec: ECParameterSpec ECKey.getParams() and ECParameterSpec is using java.security.spec.EllipticCurve. This design makes it pretty confusing to use ECPublicKey/ECPrivateKey/ECKey for RFC 7748 (Edwards curve form and Montgomery curve form). Can EllipticCurve be extended to support more forms? The java.security.spec.EllipticCurve defines two methods to get the coefficients of Weierstrass form. public BigInteger getA() public BigInteger getB() The 'A' and 'B' may not exist in other forms, for example the (3)(4)(5) forms above. While, the spec might be able to be updated by throwing UnsupportedOperationException for getA() and getB() for the (3)(4)(5) forms, and define new extended classes for new forms, like: public MCEllipticCurve extends EllipticCurve // Montgomery curve public EDEllipticCurve extends EllipticCurve // Edwards curve Instead of converting, I was thinking about mapping. E.g. Montgomery A and B matches the A and B of the curve. But the "x" of the Montgomery point is just the "x" of the ECPoint with the "y" left as null. For Edwards, it looks like you would map "d" to A. For [3] I'd map "r" to A. I'd leave B as null for both- no reason to throw an unsupported exception as the code generally has a clue about what types of keys they're dealing with (or we provide a marker so they can figure it out). The conversion in and out for points is a conversion from little endian to big endian and vice versa, but that only has to be done if you're importing or exporting a parameter set and that's an implementation issue not an API issue. Basically, all the math is BigIntegers under the hood. The curve25519 RFC specifies an implementation that's little endian, but the actual math is just math and things like the public key is really just a BigInteger. Old code would just continue to work - since it would not be using the new curves. New code would have to look for the curve type marker (e.g. the ECField) if there was the possibility of confusion. I understand your points. The mapping may be confusing to
Re: JCA design for RFC 7748
Hi, I want to extend the comment a little bit. 1. The background A elliptic curve is determined by either an equation of form y^2 = x^3 + ax + b(1) [Weierstrass form] or y^2 + xy = x^3 + ax^2 + b.(2) However, some other forms may also be used. For example: y^2 = x(x-1)(x-r) (3) or By^2 = x^3 + Ax^2 + x (4) [RFC 7748, Montgomery curve] x^2 + y^2 = 1 + dx^2y^2 (5) [RFC 7748, Edwards curve] In general, any elliptic curve can be written in Weierstrass form (1) or (2). That's, Montgomery curve and Edwards curve can be expressed in Weierstrass form. 2. Where we are now? In JDK, an elliptic curve is defined in the Weierstrass form ((1)/(2)). See java.security.spec.EllipticCurve: EllipticCurve(ECField field, BigInteger a, BigInteger b) In theory, the existing APIs can be used for RFC 7748, by converting the Montgomery curve and Edwards curve to the Weierstrass form. However, the conversion can be misleading and complicate the implementation significantly. For example, before using a point Weierstrass form (x, y), the implementation need to convert it to Montgomery curve (x', -) so as to use the fully potential of RFC 7748. The curves returned in public APIs need to use (x, y), while the implementation need to use (x', y'). It's very confusing and the compatibility impact could be significant. For example: public something(ECPublicKey ecPublicKey) { // Problem: If no other information, it is unclear // whether the ecPublicKey can be used for a particular // signature verification or not when the RFC 7748/8032 // get supported. // Problem: an old application may use ecPublicKey for // the old style operation, even the ecPublicKey is supposed // to be x25519. It's not easy to control the behavior in // legacy application code, and may introduce unexpected // security issues. } public KeyAgreement getKeyAgreement(AlgorithmParameterSpec aps) { // Problem: the code bellow should be comment in the current // code. However, the ECParameterSpec may not be able to use // for the old style "EC" key agreement. // // JDK crypto provider can take special action to avoid this // issue in the JCA/JCE implementation. But it cannot be // granted other provider can do this as well, and old // provider may run into problems as well. if (aps instance of ECParameterSpec) { return KeyAgreement.getInstance("EC"); } } What's the problem with ECPublicKey/ECPrivateKey/ECKey? It's mainly about the ECParameterSpec: ECParameterSpec ECKey.getParams() and ECParameterSpec is using java.security.spec.EllipticCurve. This design makes it pretty confusing to use ECPublicKey/ECPrivateKey/ECKey for RFC 7748 (Edwards curve form and Montgomery curve form). Can EllipticCurve be extended to support more forms? The java.security.spec.EllipticCurve defines two methods to get the coefficients of Weierstrass form. public BigInteger getA() public BigInteger getB() The 'A' and 'B' may not exist in other forms, for example the (3)(4)(5) forms above. While, the spec might be able to be updated by throwing UnsupportedOperationException for getA() and getB() for the (3)(4)(5) forms, and define new extended classes for new forms, like: public MCEllipticCurve extends EllipticCurve // Montgomery curve public EDEllipticCurve extends EllipticCurve // Edwards curve However, I'm not very sure of the compatibility impact (see above). 3. Where we are not now? Using named curves is popular. There is a ECGenParameterSpec class using named curves: ECGenParameterSpec ecgp = new ECGenParameterSpec(secp256r1); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); kpg.initialize(ecpg); KeyPair kp = kpg.generateKeyPair(); ECPublicKey pubKey = (ECPublicKey)kp.getPublic(); String keyAlgorithm = pubKey.getAlgorithm(); // "EC" However, it is used for key generation only. Once the keys are generated, there is no public API to know the name of the curve in ECKey. ECKey.getAlgorithm() will return "EC" only. If it is required to known whether a key is of a named curve, the solution is not straightforward. 4. A general proposal Support named curves could be a solution for #2 and #3 concerns above. For named curves, the parameters are defined explicitly. So, it is REQUIRED to have the public APIs for named curves' parameters any more. It can be something hidden in the implementation layer. The key pair generation may looks like: KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECWithSecp256k1"); KeyPair kp = kpg.generateKeyPair(); PublicKey pubKey = kp.getPublic(); String keyAlgorithm = pubKey.getAlgorithm(); // "ECWithSecp256k1" As no explicit parameters is required, the
Re: JCA design for RFC 7748
On 8/10/2017 9:44 AM, Adam Petcher wrote: 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? There are uses for changing out the base point. PAKE and SPAKE use similar math (e.g. G^s*sharedSecret is the equivalent of a new base point). There are uses for private curves - e.g. when you want to actually be sure that the curve was randomly generated (sort of the same argument that got us to Curve25519 in the first place). There are the whole set of Edwards curves that are mostly not included in any provider (except possible Microsoft's) as of yet. Basically, you're trying to argue that there are no better curves (for the 'new' math) than have already been specified and there never will be. I think that's a very shortsighted argument. Later, Mike
Re: CSR Review for 8159544: Remove deprecated classes in com.sun.security.auth.**
On 8/9/17 8:02 PM, Weijun Wang wrote: Looks fine. Should the specification part be formatted with and fixed fonts? Fixed. Can you add your name as Reviewer (you need to edit the CSR and add your name to the "Reviewed By" box). Thanks, Sean Thanks Max On Aug 10, 2017, at 3:15 AM, Sean Mullanwrote: Max, Could you please review the following CSR: https://bugs.openjdk.java.net/browse/JDK-8186047 Thanks, Sean
Re: JCA design for RFC 7748
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 java.security.spec.NamedParameterSpec (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 java.security.spec 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 java.security.interfaces for RFC 7748 public/private keys. Public/private key implementation classes will implement java.security.PublicKey and java.security.PrivateKey, 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 sun.security.ec.X509Key and sun.security.ec.PKCS8Key, 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.init(kp.getPrivate()); 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