提问者:小点点

Android尝试从公钥字节数组获取公钥:java. lang.IllegalArgumentException:无效的点编码0x30


我应该接收未压缩(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;
    }

共1个答案

匿名用户

因为很多人看了这个问题,我要在这里回答它:只要让自己舒服并使用适用于Android的OpenSSL库。我们的后端用它来生成它的密钥,我也用过它,它的工作原理就像一个魅力。