I'm trying to send web push notifications to my browser and am able to subscribe successfully. I get a subscription object with "an elliptic curve Diffie–Hellman public key on P-256 curve".
I want to convert this string to a public key in Java but keep getting a invalid key format exception.
Here's the code that I'm trying:
String publicK = "BBoN_OkTfE_0uObues82qHr96z8x3nepYoUwCBoftFDS_Vgx2MUHN1vAFxc1eDiyDrvmZ2bQ4sJq3F8Qz71RWI0=";
byte[] publicBytes = publicK.getBytes();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Could someone help me with this please? Encryption noob here :/
For my code, I used java 1.7 and BouncyCastle library. If you use maven, just add to your pom.xml:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
Or download the jars in BouncyCastle site. This is a cryptography API for java, with lots of useful stuff (including classes to handle elliptic curves keys).
The code for reading the public key and converting to an object is:
import java.security.KeyFactory;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.ECPointUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.util.encoders.Base64;
// you need to add the BouncyCastle provider to use its functionalities
Security.addProvider(new BouncyCastleProvider());
String publicK = "BBoN_OkTfE_0uObues82qHr96z8x3nepYoUwCBoftFDS_Vgx2MUHN1vAFxc1eDiyDrvmZ2bQ4sJq3F8Qz71RWI0=";
// publicK is encoded in base64, so you need to decode it first
byte[] publicBytes = Base64.decode(publicK.getBytes());
// spec for P-256 curve
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
// create a KeyFactory with ECDSA (Elliptic Curve Diffie-Hellman) algorithm and use BouncyCastle as the provider
KeyFactory kf = KeyFactory.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME);
// code below just creates the public key from the bytes contained in publicK
// using the curve parameters (spec variable)
ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = ECPointUtil.decodePoint(params.getCurve(), publicBytes);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
System.out.println(pk.toString());
Output:
EC Public Key
X: 1a0d00e9137c4034b8e6ee7acf36a87afdeb3f31de77a9628530081a1fb450d2
Y: 15831d8c507375bc01717357838b20ebbe66766d0e2c26adc5f10cfbd51588d
Notes:
I'm not aware of all the math behind elliptic curve keys, just the basic idea. I know that a curve has parameters like G and n (which are obtained via getG() and getN() methods) and that there are some "standard pre-defined" curves (like P-256) that you can get using ECNamedCurveTable.getParameterSpec().
You can take a look at all the math details if you want. There is also a list of different standard curves and which ones are considered secure.
ECPublicKey extends PublicKey, so you can use it just like a PublicKey
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With