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

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

MainActivity.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); } 

logcat的:

 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] 

如果有人可以解释这个exception的原因,并帮助我从String获取PublicKey实例的小片段,那将会很棒。

参考文献:

  • http://www.programcreek.com/java-api-examples/index.php?api=org.bouncycastle.asn1.ASN1InputStream

  • http://www.bouncycastle.org/wiki/display/JA1/Elliptic+Curve+Key+Pair+Generation+and+Key+Factories

提前致谢!!

更新:

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

 ASN1Primitive.fromByteArray(data); 

例外:

 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);