Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating ECPublicKey from byte array

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);
}
like image 290
Simon Avatar asked Jan 09 '23 23:01

Simon


1 Answers

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));
    }
}
like image 174
Maarten Bodewes Avatar answered Jan 18 '23 23:01

Maarten Bodewes