Search code examples
javacryptographybouncycastleelliptic-curveecdsa

Elliptic Curve Cryptography (ECDSA) Private Key Matches Public Key (Java - Bouncy Castle)


I try to use Elliptic Curve Digital Signature Algorithm (ECDSA) with Bouncy Castle and Java. I want to generate a public key and private key. The problem is that these keys have the exact same values. Let's look at the code:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
ECGenParameterSpec params = new ECGenParameterSpec("prime256v1");
keyPairGenerator.initialize(params, secureRandom); 
KeyPair keyPair = keyPairGenerator.generateKeyPair();

I use the java.security related classes:

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;

Everything is working fine, but the problem is that the public key matches the private key. I am confused because the public key should be a point on the elliptic curve (so far so good). The private key should be an integer, but it is the same point (on the curve) as the public key. Am I missing something? When I print the public key and private key values:

EC Public Key [f9:63:ec:0b:ca:a4:c6:f8:50:d0:2f:29:8b:23:10:13:d8:1c:2f:16]
        X: 818af4b0ed955e273c4d81c1480db282293b95881b7f04dba897da0cef3a91de
        Y: 3b00a30ced960780a8a830b928601dbfd32ac09e8e19e2297f8831f66e80fd15

EC Private Key [f9:63:ec:0b:ca:a4:c6:f8:50:d0:2f:29:8b:23:10:13:d8:1c:2f:16]
        X: 818af4b0ed955e273c4d81c1480db282293b95881b7f04dba897da0cef3a91de
        Y: 3b00a30ced960780a8a830b928601dbfd32ac09e8e19e2297f8831f66e80fd15

Solution

  • You just did system out on the object. These are indeed the public specs. If you check the actual bytes of the key, you'll see the difference:

    @Test
    void stackOverflowQuestion() throws Exception{
        Security.addProvider(new BouncyCastleFipsProvider());
    
        final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", BouncyCastleFipsProvider.PROVIDER_NAME);
        final SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        final ECGenParameterSpec params = new ECGenParameterSpec("prime256v1");
        keyPairGenerator.initialize(params, secureRandom);
        final KeyPair keyPair = keyPairGenerator.generateKeyPair();
    
        System.out.println(keyToBase64String(keyPair.getPrivate()));
        System.out.println(keyToBase64String(keyPair.getPublic()));
    }
    
    public static String keyToBase64String(final Key key) {
        return bytesToBase64(key.getEncoded());
    }
    
    private static String bytesToBase64(final byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }
    

    output:

    MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQggbwdSOULxslgm+ckKNW9d0gtPAPUrSjU29Rtk6szTeKgCgYIKoZIzj0DAQehRANCAASP3lAcUGCqmvYUt9hZEjPArtcdBlUYC3Sac9XSpZFRkFnWmIHxwx40ejFXxE9U2mq+VDMe21rjXBvdnqxHyCV4
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj95QHFBgqpr2FLfYWRIzwK7XHQZVGAt0mnPV0qWRUZBZ1piB8cMeNHoxV8RPVNpqvlQzHtta41wb3Z6sR8gleA==
    

    Also, don't use SHA1PRNG. You can trust the provide secure random of BC. Use instead: keyPairGenerator.initialize(params);