Reputation: 700
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.509
format (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
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