I get a 64 uncompressed public key and need to run ECDH to generate a shared secret.
In order to call ECDH I need to convert the byte array to PublicKey
and I am using the following code I have found in this forum:
public static void setOtherPublicKey(byte[] publicKeyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException
{
try {
//EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
KeyFactory generator = KeyFactory.getInstance("EC");
//PrivateKey privateKey = generator.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
blePubKey = generator.generatePublic(publicKeySpec);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to create KeyPair from provided encoded keys", e);
}
}
This code throws an InvalidKeySpecException
.
As example, the public key of the other party is:
9b5e9a5a971877530c9cadbbea93c2ee2483d65052678f745bad79f110173520
54019832e11376537a76c4defd0b3dfdc667a974239147f323cdcfd2baa39892
Adding the code after getting the answers below:
public static void setOtherPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException
{
// first generate key pair of your own
ECPublicKey pubKey = (ECPublicKey) SecPage.g_kpA.getPublic();
ECParameterSpec params = pubKey.getParams();
int keySizeBytes = params.getOrder().bitLength() / Byte.SIZE;
// get the other party 64 bytes
//byte [] otherPub = crypto.getBlePubKeyBytes();
byte[] otherPub = hexStringToByteArray("ac2bdd28fce5c7b181b34f098b0934742281246ed907a5f646940c1edcb724e7c7358356aebea810322a8e324cc77f376df4cabd754110ad41ec178c0a6b8e5f");
ByteArrayBuffer xBytes = new ByteArrayBuffer(33);
ByteArrayBuffer yBytes = new ByteArrayBuffer(33);
byte[] zero = {(byte)0x00};
xBytes.append(zero, 0, 1);
xBytes.append(otherPub, 0, 32);
yBytes.append(zero, 0, 1);
yBytes.append(otherPub, 32, 32);
// generate the public key point
BigInteger x = new BigInteger(xBytes.buffer());
BigInteger y = new BigInteger(yBytes.buffer());
ECPoint w = new ECPoint(x, y);
// generate the key of the other side
ECPublicKeySpec otherKeySpec = new ECPublicKeySpec(w , params);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
blePubKey = (ECPublicKey) keyFactory.generatePublic(otherKeySpec);
}
Well, whaty'know, you can actually do this... explanation in the comments.
public class ECDHPub {
private static ECPublicKey decodeECPublicKey(ECParameterSpec params,
final byte[] pubkey) throws NoSuchAlgorithmException,
InvalidKeySpecException {
int keySizeBytes = params.getOrder().bitLength() / Byte.SIZE;
int offset = 0;
BigInteger x = new BigInteger(1, Arrays.copyOfRange(pubkey, offset,
offset + keySizeBytes));
offset += keySizeBytes;
BigInteger y = new BigInteger(1, Arrays.copyOfRange(pubkey, offset,
offset + keySizeBytes));
ECPoint w = new ECPoint(x, y);
ECPublicKeySpec otherKeySpec = new ECPublicKeySpec(w, params);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey otherKey = (ECPublicKey) keyFactory
.generatePublic(otherKeySpec);
return otherKey;
}
private static byte[] encodeECPublicKey(ECPublicKey pubKey) {
int keyLengthBytes = pubKey.getParams().getOrder().bitLength()
/ Byte.SIZE;
byte[] publicKeyEncoded = new byte[2 * keyLengthBytes];
int offset = 0;
BigInteger x = pubKey.getW().getAffineX();
byte[] xba = x.toByteArray();
if (xba.length > keyLengthBytes + 1 || xba.length == keyLengthBytes + 1
&& xba[0] != 0) {
throw new IllegalStateException(
"X coordinate of EC public key has wrong size");
}
if (xba.length == keyLengthBytes + 1) {
System.arraycopy(xba, 1, publicKeyEncoded, offset, keyLengthBytes);
} else {
System.arraycopy(xba, 0, publicKeyEncoded, offset + keyLengthBytes
- xba.length, xba.length);
}
offset += keyLengthBytes;
BigInteger y = pubKey.getW().getAffineY();
byte[] yba = y.toByteArray();
if (yba.length > keyLengthBytes + 1 || yba.length == keyLengthBytes + 1
&& yba[0] != 0) {
throw new IllegalStateException(
"Y coordinate of EC public key has wrong size");
}
if (yba.length == keyLengthBytes + 1) {
System.arraycopy(yba, 1, publicKeyEncoded, offset, keyLengthBytes);
} else {
System.arraycopy(yba, 0, publicKeyEncoded, offset + keyLengthBytes
- yba.length, yba.length);
}
return publicKeyEncoded;
}
public static void main(String[] args) throws Exception {
// (only) required for named curves other than those used in JCE
Security.addProvider(new BouncyCastleProvider());
// create local and remote key
KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", "BC");
ECGenParameterSpec genspec = new ECGenParameterSpec("brainpoolp256r1");
kpgen.initialize(genspec);
KeyPair localKeyPair = kpgen.generateKeyPair();
KeyPair remoteKeyPair = kpgen.generateKeyPair();
// test generation
byte[] encodedRemotePublicKey = encodeECPublicKey((ECPublicKey) remoteKeyPair
.getPublic());
// test creation
ECPublicKey remoteKey = decodeECPublicKey(
((ECPublicKey) localKeyPair.getPublic()).getParams(),
encodedRemotePublicKey);
// local key agreement
KeyAgreement localKA = KeyAgreement.getInstance("ECDH");
localKA.init(localKeyPair.getPrivate());
localKA.doPhase(remoteKey, true);
byte[] localSecret = localKA.generateSecret();
// remote key agreement
KeyAgreement remoteKA = KeyAgreement.getInstance("ECDH");
remoteKA.init(remoteKeyPair.getPrivate());
remoteKA.doPhase((ECPublicKey) localKeyPair.getPublic(), true);
byte[] remoteSecret = localKA.generateSecret();
// validation
System.out.println(Arrays.equals(localSecret, remoteSecret));
}
}
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