java - 从 Base64 编码的字符串中检索 ECC 公钥

标签 java android base64 public-key-encryption spongycastle

我一直在尝试使用 Base64 编码的 ECC 公钥创建 java.security.PublicKey 的实例。

主 Activity .java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        byte[] data = decodePublicKey("AsIAEFjzIcX+Kvhe8AmLoGUc8aYAEAwf5ecREGZ2u4RLxQuav/A=");
        PublicKey publicKey = loadPublicKey("secp128r1", data);

        Log.d(TAG, publicKey.toString());
    } catch (SQLException | IOException | GeneralSecurityException e) {
        Log.e(TAG, e.getMessage(), e);
    }
}

private byte[] decodePublicKey(String s) throws UnsupportedEncodingException {
    return Base64.decode(s, Base64.DEFAULT);
}

public PublicKey loadPublicKey(String curve, byte[] data)
        throws SQLException, IOException, GeneralSecurityException {
    Log.d(TAG, Arrays.toString(data));
    // [2, -62, 0, 16, 88, -13, 33, -59, -2, 42, -8, 94, -16, 9, -117, -96, 101, 28, -15, -90, 0, 16, 12, 31, -27, -25, 17, 16, 102, 118, -69, -124, 75, -59, 11, -102, -65, -16]
    Log.d(TAG, "Length :" + String.valueOf(data.length));

    KeyFactory factory = KeyFactory.getInstance("EC", "SC");
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curve);
    ECCurve eccCurve = spec.getCurve();
    Log.d(TAG, "Curve: " + curve);

    EllipticCurve ellipticCurve = EC5Util.convertCurve(eccCurve, spec.getSeed());

    // decoding point fails, 
    // line no 66.
    ECPoint point = ECPointUtil.decodePoint(ellipticCurve, data);
    ECParameterSpec params = EC5Util.convertSpec(ellipticCurve, spec);

    ECPublicKeySpec keySpec = new ECPublicKeySpec(point, params);
    return factory.generatePublic(keySpec);
}

日志:

Process: com.example.eccdemo, PID: 21151
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.eccdemo/com.example.eccdemo.MainActivity}: java.lang.IllegalArgumentException: Incorrect length for compressed encoding
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2329)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2389)
        at android.app.ActivityThread.access$900(ActivityThread.java:147)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1296)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
 Caused by: java.lang.IllegalArgumentException: Incorrect length for compressed encoding
        at org.spongycastle.math.ec.ECCurve.decodePoint(ECCurve.java:349)
        at org.spongycastle.jce.ECPointUtil.decodePoint(ECPointUtil.java:52)
        at com.example.eccdemo.MainActivity.loadPublicKey(MainActivity.java:66)
        at com.example.eccdemo.MainActivity.onCreate(MainActivity.java:45)
        at android.app.Activity.performCreate(Activity.java:5933)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2282)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2389)
        at android.app.ActivityThread.access$900(ActivityThread.java:147)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1296)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)

进一步检查:

在 Logcat 中,在打印解码字节时,它们实际上与服务器上的不同:

    Log.d(TAG, Arrays.toString(data));
    [2, -62, 0, 16, 88, -13, 33, -59, -2, 42, -8, 94, -16, 9, -117, -96, 101, 28, -15, -90, 0, 16, 12, 31, -27, -25, 17, 16, 102, 118, -69, -124, 75, -59, 11, -102, -65, -16]

在 python 控制台中:

In [131]: [_ for _ in ap.public_key.tobytes()]
Out[131]: [2, 194, 0, 16, 88, 243, 33, 197, 254, 42, 248, 94, 240, 9, 139, 160, 101, 28, 241, 166, 0, 16, 12, 31, 229, 231, 17, 16, 102, 118, 187, 132, 75, 197, 11, 154, 191, 240]

如果有人能解释这个异常的原因,并帮助我处理从字符串中获取 PublicKey 实例的小 fragment ,那就太好了。

引用资料:

提前致谢!

更新:

当尝试使用下面的行加载 ASN1Primitive 时,它​​会抛出以下异常:

ASN1Primitive.fromByteArray(data);

异常(exception):

java.io.IOException: DER length more than 4 bytes: 66
        at org.spongycastle.asn1.ASN1InputStream.readLength(ASN1InputStream.java:347)
        at org.spongycastle.asn1.ASN1InputStream.readLength(ASN1InputStream.java:112)
        at org.spongycastle.asn1.ASN1InputStream.readObject(ASN1InputStream.java:237)
        at org.spongycastle.asn1.ASN1Primitive.fromByteArray(ASN1Primitive.java:30)
        at com.example.eccdemo.MainActivity.onCreate(MainActivity.java:48)
        at android.app.Activity.performCreate(Activity.java:5933)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2282)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2389)
        at android.app.ActivityThread.access$900(ActivityThread.java:147)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1296)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)

最佳答案

您的 base64 编码数据长度为 38 字节,并且似乎不在 ASN1 中。也许这是个问题。另一方面,只要您可以从数据中提取 X 和 Y,就可以通过这种方式生成公钥:

      String hexPubKeyXY = "01f82bfb2f0a3e988adc3d053d8e6ff878154306e402d871b7d6000823a1397f";
      String hexX = hexPubKeyXY.substring(0, 32);
      String hexY = hexPubKeyXY.substring(32);
      ECPoint point = new ECPoint(new BigInteger(hexX, 16), new BigInteger(hexY, 16));

      AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC");
      parameters.init(new ECGenParameterSpec("secp128r1"));
      ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);

      ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, ecParameters);

      PublicKey key = KeyFactory.getInstance("EC", "SunEC").generatePublic(pubKeySpec);

关于java - 从 Base64 编码的字符串中检索 ECC 公钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30868936/

相关文章:

java - 访问给定对象的值

android - 通过调试或发布过滤 androidDependency

android Activity 不是全屏 Theme.Dialog 应用程序已停止

java - 无限循环卡在 run() - 方法(Android 模拟器)

javascript - 在本地存储中存储 .jpg 文件

javascript - 如何将数组转换为可能的最短字符串

java - 为什么两个日期类一个在 java.util.Date 和 java.sql.Date 中?

java.lang.NoClassDefFoundError : org/htmlparser/util/ParserException

java - 按值对 Map<Key, Value> 进行排序

c# - 在 MySQL 中存储字符串