【问题标题】:BouncyCastle PEMParser throws NoClassDefFound and VerifyError using GenyMotion EmulatorBouncyCastle PEMParser 使用 GenyMotion 仿真器抛出 NoClassDefFound 和 VerifyError
【发布时间】:2014-06-10 09:15:47
【问题描述】:

由于三星设备非常糟糕,我转而使用 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 都让人心疼,我也不知道怎么追了.. :/

【问题讨论】:

  • 显然从 Google Nexus One 切换到 Google Nexus 4 修复了这些错误。我想这确实是一个模拟器问题。
  • 您好,您的nexus 1 和nexus 4 使用的是哪个Android 版本?我为 genymotion 工作,并希望进一步调查。
  • 您好,设置如下,Google Nexus One - 2.3.7 - API 10 - 480 x 800; AOSP 版本 2.3.7; Genymotion 版本 2.2.2 ;;;谷歌 Nexus 4 - 4.1.1 - API 16 - 768x1280; AOSP 版本 4.1.1; Genymotion 版本 2.2.2。我还想指出,在 Nexus One 上,listItemClick 给出了不稳定的结果。我所做的只是更改列表项单击位置的背景,但它是“镜像”选择。就像,在适配器显示的总共 4 个列表中,单击索引 1 选择了 2,然后选择了 1。很奇怪,如果你愿意,我可以发布代码。

标签: android noclassdeffounderror bouncycastle genymotion verifyerror


【解决方案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'

【讨论】:

  • 太棒了。感谢您的信息。我将使用 SpongyCastle 来解决这个问题。我也很高兴模拟器没有任何问题。再次感谢。 :)
猜你喜欢
  • 2020-03-31
  • 2019-08-07
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 2013-12-30
  • 1970-01-01
相关资源
最近更新 更多