0

由于三星设备非常糟糕,我转而使用 GenyMotion 作为 Android 模拟器。但是,在我拥有的三星 Note 上运行的代码在模拟器上因 NoClassDefFoundError 而崩溃。

06-10 09:02:15.630: E/AndroidRuntime(2231): FATAL EXCEPTION: main
06-10 09:02:15.630: E/AndroidRuntime(2231): java.lang.NoClassDefFoundError: org.bouncycastle.asn1.ASN1Primitive
06-10 09:02:15.630: E/AndroidRuntime(2231):     at org.bouncycastle.pkcs.PKCS10CertificationRequest.parseBytes(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at org.bouncycastle.pkcs.PKCS10CertificationRequest.<init>(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at org.bouncycastle.openssl.PEMParser$PKCS10CertificationRequestParser.parseObject(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at org.bouncycastle.openssl.PEMParser.readObject(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at com.example.MyFragment.convertPemToPKCS10CertificationRequest(MyFragment.java:254)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at com.example.MyFragment.testReadCertificateSigningRequest(MyFragment.java:145)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at com.example.MyFragment.onClick(MyFragment.java:87)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.view.View.performClick(View.java:2485)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.view.View$PerformClick.run(View.java:9080)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.os.Handler.handleCallback(Handler.java:587)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.os.Handler.dispatchMessage(Handler.java:92)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.os.Looper.loop(Looper.java:130)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at android.app.ActivityThread.main(ActivityThread.java:3683)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at java.lang.reflect.Method.invokeNative(Native Method)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at java.lang.reflect.Method.invoke(Method.java:507)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-10 09:02:15.630: E/AndroidRuntime(2231):     at dalvik.system.NativeStart.main(Native Method)

我也尝试过不同的版本,它并没有真正帮助,事实上,PEMParser 显然在 1.47 中甚至不可用。代码如下:

   private final String csrPEM = "-----BEGIN CERTIFICATE REQUEST-----\n"
         + "MIICwjCCAaoCAQAwfTELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0Zsb3JpZGExEzAR\n"
         + "BgNVBAcTCkJvY2EgUmF0b24xGzAZBgNVBAoTEkxvb25leSBUb29ucywgSW5jLjEU\n"
         + "MBIGA1UECxMLRGV2ZWxvcG1lbnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMIIBIjAN\n"
         + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiJCj31d1Rp+aKz/GTkedaiS/VSCc\n"
         + "PRARYgXukobjgBHx46HjldAcfg/DoANn5lEQaFxaIZJLbZ/AdLUyw/hUbU0CjWXv\n"
         + "pN3Ep3o9XgRTPkIFoI22VOI/O2ZLjBq/E4DWyVmv+vG6BK0LRh7hykzPCw6KIRR9\n"
         + "NCmUMJMQX5d5P/r1lR5H399pnLcLsrHoWDwBSEDgkGWyxnvEB0+/bIz42T3qnlFt\n"
         + "7avarxlHG2p5DoRTf8GJ+6imY88ZeBW/Nk18aDINsAHWLv383JICIAsZ3VuMk8m/\n"
         + "Z/Z5b21zIuZECDJjZjvAAjr/shVLB+Pck5+HJy6tqj79MJOQu+jKIrK8VwIDAQAB\n"
         + "oAAwDQYJKoZIhvcNAQEFBQADggEBAGtuAAHG4OC9jSRjGWSqfMXTDMz9tgekDREA\n"
         + "SYv5QIrOXsMzwbgDw8LxRJZEskl4JJOnjwEvUXWUF1M6XmG2h358nOnrkOlsumHw\n"
         + "Tx5gGSr6S6aJO/HG46erctE8aWpnFZYMfuEkul4ApsIufL7Bxqs3NHZWcrWBlLIP\n"
         + "aVCKx1FPRMC36Tj3EslbuUB/iTRt90Nfq1IxHMIKiwCiSNJSqfRVLANhI8MUbOjB\n"
         + "CBly1wcH68WWNkyvHVvbcF/B9AfYG9AqWjZjygKpyf81VZWctXhDc8UtomqrblXN\n"
         + "mvz4RKpIhZQLuuxlBrdzJkPm2sOdtdZghebCRRVWdjsig4sylgQ=\n"
         + "-----END CERTIFICATE REQUEST-----";

   public void testReadCertificateSigningRequest()
   {

      PKCS10CertificationRequest csr = convertPemToPKCS10CertificationRequest(csrPEM);
      if (csr == null)
      {
         System.out.println("FAIL!");
      }
      else
      {
         X500Name x500Name = csr.getSubject();
         System.out.println("x500Name is: " + x500Name + "\n");

         // country is 2.5.4.6
         System.out.println("COUNTRY: " + getX500Field(COUNTRY, x500Name));
         // state is 2.5.4.8
         System.out.println("STATE: " + getX500Field(STATE, x500Name));
         // locale is 2.5.4.7
         System.out.println("LOCALE: " + getX500Field(LOCALE, x500Name));
      }
   }

   private String getX500Field(String asn1ObjectIdentifier, X500Name x500Name)
   {
      RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(asn1ObjectIdentifier));
      String retVal = null;
      for (RDN item : rdnArray)
      {
         retVal = item.getFirst().getValue().toString();
      }

      return retVal;
   }


   private PKCS10CertificationRequest convertPemToPKCS10CertificationRequest(String pem)
   {
      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
      PKCS10CertificationRequest csr = null;
      ByteArrayInputStream pemStream = null;
      try
      {
         pemStream = new ByteArrayInputStream(pem.getBytes("UTF-8"));
      }
      catch (UnsupportedEncodingException ex)
      {
         Log.e(getClass().getSimpleName(), "UnsupportedEncodingException, convertPemToPublicKey", ex);
      }

      Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
      PEMParser pemParser = null;
      try
      {
         pemParser = new PEMParser(pemReader);
         Object parsedObj = pemParser.readObject();
         System.out.println("PemParser returned: " + parsedObj);
         if (parsedObj instanceof PKCS10CertificationRequest)
         {
            csr = (PKCS10CertificationRequest) parsedObj;
         }
      }
      catch (IOException ex)
      {
         Log.e(getClass().getSimpleName(), "IOException, convertPemToPublicKey", ex);
      }
      finally
      {
         if (pemParser != null)
         {
            IOUtils.closeQuietly(pemParser);
         }
      }
      return csr;
   }

而且我也得到了VerifyError ...

06-10 09:09:18.920: E/AndroidRuntime(2295): FATAL EXCEPTION: main
06-10 09:09:18.920: E/AndroidRuntime(2295): java.lang.VerifyError: org.bouncycastle.cert.X509CertificateHolder
06-10 09:09:18.920: E/AndroidRuntime(2295):     at org.bouncycastle.openssl.PEMParser$X509CertificateParser.parseObject(Unknown Source)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at org.bouncycastle.openssl.PEMParser.readObject(Unknown Source)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at com.example.MyFragment.convertPemToX509Certificate(MyFragment.java:214)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at com.example.MyFragment.testReadCertificateSigningRequest(MyFragment.java:146)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at com.example.MyFragment.onClick(MyFragment.java:87)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.view.View.performClick(View.java:2485)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.view.View$PerformClick.run(View.java:9080)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.os.Handler.handleCallback(Handler.java:587)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.os.Handler.dispatchMessage(Handler.java:92)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.os.Looper.loop(Looper.java:130)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at android.app.ActivityThread.main(ActivityThread.java:3683)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at java.lang.reflect.Method.invokeNative(Native Method)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at java.lang.reflect.Method.invoke(Method.java:507)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-10 09:09:18.920: E/AndroidRuntime(2295):     at dalvik.system.NativeStart.main(Native Method)

代码如下:

   public void testReadCertificateSigningRequest()
   {
      X509CertificateHolder csr2 = convertPemToX509Certificate(testCSR);

      if (csr2 == null)
      {
         System.out.println("TOTAL FAIL!");
      }
      else
      {
         X500Name name = csr2.getSubject();
         System.out.println("x500Name is: " + name + "\n");
         System.out.println("Common Name: " + getX500Field(COMMON_NAME, name));
         // country is 2.5.4.6
         System.out.println("COUNTRY: " + getX500Field(COUNTRY, name));
         // state is 2.5.4.8
         System.out.println("STATE: " + getX500Field(STATE, name));
         // locale is 2.5.4.7
         System.out.println("LOCALE: " + getX500Field(LOCALE, name));
      }
   }

   private X509CertificateHolder convertPemToX509Certificate(String pem)
   {
      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
      X509CertificateHolder csr = null;
      ByteArrayInputStream pemStream = null;
      try
      {
         pemStream = new ByteArrayInputStream(pem.getBytes("UTF-8"));
      }
      catch (UnsupportedEncodingException ex)
      {
         Log.e(getClass().getSimpleName(), "UnsupportedEncodingException, convertPemToPublicKey", ex);
      }

      Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
      PEMParser pemParser = null;
      try
      {
         pemParser = new PEMParser(pemReader);
         Object parsedObj = pemParser.readObject();
         System.out.println("PemParser returned: " + parsedObj);
         if (parsedObj instanceof X509CertificateHolder)
         {
            csr = (X509CertificateHolder) parsedObj;
         }
      }
      catch (IOException ex)
      {
         Log.e(getClass().getSimpleName(), "IOException, convertPemToPublicKey", ex);
      }
      finally
      {
         if (pemParser != null)
         {
            IOUtils.closeQuietly(pemParser);
         }
      }
      return csr;
   }

所以我真的无法判断这是否是模拟的 Google Nexus One、GenyMotion 或我的代码出现的错误。NoClassDefFound 和 VerifyError 都令人痛苦,我不知道如何追踪它.. :/

4

1 回答 1

1

免责声明:我为 Genymotion 工作

这不是模拟器问题,而是 Android 问题。旧的 Android 版本(Gingerbread 现在已经 4 岁了)附带了非常古老的 BouncyCastle 实现。见(https://code.google.com/p/android/issues/detail?id=3280

您的模拟器实际上是在警告您,您的代码可能无法2.3.7 的 Android 设备上运行。

一种解决方案是在您的应用程序中发布最新的 BouncyCastle 实现。但是你会遇到冲突,因为它的包名与手机上的包名相同。为避免这种情况,您可以使用 SpongyCastle,一个最新的 BouncyCastle,但重命名以避免包名冲突。见http://rtyley.github.io/spongycastle/

我只是将 spongycastle 的依赖项添加到我的 gradle 构建文件中,修复了导入以使用 SpongyCastle,并且您的代码在 Genymotion Nexus One 上完美运行。

compile 'com.madgag.spongycastle:core:1.50.0.0'
compile 'com.madgag.spongycastle:prov:1.50.0.0'
compile 'com.madgag.spongycastle:pkix:1.50.0.0'
于 2014-06-11T09:06:00.057 回答