Ali Has
Ali Has

Reputation: 700

Android Trying to get Public Key from public key byte array: java.lang.IllegalArgumentException: Invalid point encoding 0x30

I am supposed to receive server public key ("ECDH" , "secp256k1") in HEX format, which is uncompressed (65 bytes), generate my own public key in Android which is in X.509format (88 bytes), and then generate a shared secret which must be 32 bytes. Now when I want to get server public key I ran into this error:

java.security.spec.InvalidKeySpecException: invalid KeySpec: point not on curve

The procedure: First I produce my own public key, then turn server HEX key into byte array: serverKey.getBytes() , then put it in another method below :

Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
KeyPairGenerator kpgen =KeyPairGenerator.getInstance("ECDH", "BC");
ECGenParameterSpec genspec = new ECGenParameterSpec("secp256k1");
kpgen.initialize(genspec);
KeyPair localKeyPair = kpgen.generateKeyPair();    
ECPublicKey remoteKey = decodeECPublicKey(serverKey.getBytes());
KeyAgreement localKA = KeyAgreement.getInstance("ECDH");
localKA.init(keyPair.getPrivate());
localKA.doPhase((ECPublicKey) remoteKey, true);
byte[] localSecret = localKA.generateSecret();

decodeECPublicKey is:

public static decodeECPublicKey getPublicKeyFromBytes(byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory kf = KeyFactory.getInstance("ECDH", new BouncyCastleProvider());
    ECNamedCurveSpec params = new ECNamedCurveSpec("secp256k1", spec.getCurve(), spec.getG(), spec.getN());
    ECPoint point =  ECPointUtil.decodePoint(params.getCurve(), pubKey);
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
    ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
    return pk;
}

Which upon execution, produces this error:

java.lang.IllegalArgumentException: Invalid point encoding 0x30

What am I doing wrong?

EDIT: Ok. The wrong part was serverKey.getBytes() thanks to @Topaco. Now that I have localSecret I want to encrypt a String with AES-256-CBC algorithm using first 16 bytes of localSecret as iv, and second ones as the key. I have written this code but when I send the result to the server it generates error:

public static byte[] enc(byte[] key, String toBeEnc) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException {
        Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        System.arraycopy(key, 0, iv, 0, iv.length);
        byte[] keyByte = new byte[16];
        System.arraycopy(key, 16, keyByte, 0, keyByte.length);
        Key keyF = new SecretKeySpec(keyByte, "AES");
        ecipher.init(Cipher.ENCRYPT_MODE, keyF, new IvParameterSpec(iv));
        byte[] enc = ecipher.doFinal(toBeEnc.getBytes(StandardCharsets.UTF_8));
        return enc;
    }

Upvotes: 0

Views: 2117

Answers (1)

Ali Has
Ali Has

Reputation: 700

Because many people viewed this question, I'm gonna answer it here: Just make yourself comfortable and use OpenSSL library for Android. Our backend used it to generate its key, I used it as well and it works like a charm.

Upvotes: 0

Related Questions