4

As noted in the title, I am unable to make the following code produce the ECC keyPair.

The Exception is: java.security.InvalidParameterException: unknown key size 571.

On the desktop, 571 is the max key size, and I intend to use the max key size on the Android app as well. What must I do to make it possible?

Next, is it possible to make bigger keys through other libraries both on Android and on Desktop?

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Thread thread = new Thread(){
        public void run(){
            try{
                setPriority(Thread.MAX_PRIORITY);
                SecureRandom secureRandom = new SecureRandom();
                KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
                generator.initialize(571, secureRandom);
                KeyPair keyPair = generator.generateKeyPair();
                PublicKey publicKey = keyPair.getPublic();
                PrivateKey privateKey = keyPair.getPrivate();

                System.out.println("EC public: " + publicKey.getAlgorithm() + "\t" + publicKey.getFormat());
                System.out.println("EC private: " + privateKey.getAlgorithm() + "\t" + publicKey.getFormat());
            }
            catch(Exception e){
                System.err.println("EC Exception\n" + e.toString());
                e.printStackTrace();
            }
        }
    };
    thread.start();
}
theAnonymous
  • 1,701
  • 2
  • 28
  • 62

2 Answers2

7

There is no need to use a 571 bit curve. Curves with 512 bits key size or higher provide 256 bits of security. That's plenty - until quantum computing gets of age and in that case neither will suffice. With a large quantum computer the security of Elliptic Curve cryptography using the Discrete Logarithm problem (ECDL) with a large enough quantum computer will be next to zero.

Currently most standards use either prime curves (curves over F(p)) or Edwards curves such as Curve25519 (Ed25519 and X25519). What you are using when you specify 571 is probably the curve over F(2^m) called sect571r1 standardized as K-571. That's a binary / Koblitz curve; binary curves are currently not often used and may not be available in every provider. Up to Java 18 there has been no support for binary curves.

Java 18 does support both prime and Edwards curves such as Ed25519, as you can see when looking at the Security -> Providers -> SunEC provider guide, section "Supported Elliptic Curve Names". Currently it supports secp256r1, secp384r1 and secp521r1 for signature generation and key agreement, Ed25519 and Ed448 for signature generation and X25519 and X448 for key agreement. These have been in there since Java 11, the last LTS version of Java.

Choosing specific curves this way isn't very clear and may have future consequences. What if a different curve is used because another provider is added that implements a curve of the same size?

Instead, use the following code if you want to stick to an named strong curve over a prime field:

KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
generator.initialize(new ECGenParameterSpec("secp521r1"));
KeyPair keyPair = generator.generateKeyPair();
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();

Pretty please with sugar on top, use the actual name of the curve and not just the bit size, i.e. ECGenParameterSpec. You really don't want to generate curve domain parameters yourself, nor do you want to use any curve that fits the bit size. In general, with cryptography, I would not use any default values unless a standard defines them explicitly.


You could also try and add a provider (BouncyCastle for Java and later versions of Android, SpongyCastle for earlier versions of Android) to get support for more curves. Make sure you specify the provider to be used for the generator in that case. I would seriously suggest using a named curve as argued above.

Beware that the SunEC provided implementations of KeyPairGenerator and Signature will probably insist that they can handle software defined EC keys, while they are incompatible with these curve names. That means that you need to explicitly use the BouncyCastle or SpongyCastle provider, rather than simply add the provider to the known list:

Provider bc = new BouncyCastleProvider();

KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", bc);
kpg.initialize(new ECGenParameterSpec("K-571")); // "sect571r1" also works
KeyPair kp = kpg.generateKeyPair();

Signature sig = Signature.getInstance("SHA512WithECDSA", bc);
sig.initSign(kp.getPrivate());
sig.sign();
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
0

You are restricted to a discrete set of NIST-approved EC curves, you don't have carte blanche.

In addition, if you're using a hardware-backed Android keystore (which will increasingly be the case going forward), then there is only hardware support for specific key parameter combinations - e.g at present (2020/11) only 1024- and 2048-bit RSA keys are supported in hardware, but not 4096-bit.

david.barkhuizen
  • 5,239
  • 4
  • 36
  • 38