我应该接收未压缩(65字节)的HEX格式的服务器公钥(“ECDH”、“secp256k1”),在Android中生成我自己的X.509
格式(88字节)的公钥,然后生成一个必须为32字节的共享密钥。现在,当我想获取服务器公钥时,我遇到了这个错误:
java.security. spec.InvalidKeySpecException:无效KeySpec:点不在曲线上
过程:首先我生成自己的公钥,然后将服务器HEX密钥转换为字节数组:serverKey. getBytes()
,然后将其放入下面的另一个方法中:
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();
解码ECPublicKey
是:
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;
}
在执行时,会产生以下错误:
java. lang.IllegalArgumentException:无效的点编码0x30
我做错了什么?
编辑:好的。由于@Topaco,错误的部分是serverKey. getBytes()
。现在我有了localSecret
,我想用AES-256-CBC算法加密一个String
,使用localSecret
的前16个字节作为iv,第二个字节作为密钥。我已经编写了这段代码,但是当我将结果发送到服务器时,它会产生错误:
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;
}
因为很多人看了这个问题,我要在这里回答它:只要让自己舒服并使用适用于Android的OpenSSL库。我们的后端用它来生成它的密钥,我也用过它,它的工作原理就像一个魅力。