首页 > 解决方案 > Android 试图从公钥字节数组中获取公钥:java.lang.IllegalArgumentException: Invalid point encoding 0x30

问题描述

我应该接收 HEX 格式的服务器公钥(“ECDH”,“secp256k1”),未压缩(65 字节),在 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();

decodeECPublicKey是:

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

我究竟做错了什么?

编辑: 好的。错误的部分要serverKey.getBytes()感谢@Topaco。既然我有了,localSecret我想String用 AES-256-CBC 算法加密 a,使用前 16 个字节localSecret作为 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;
    }

标签: androidsecurityencryptionopensslecdh

解决方案


推荐阅读