签名 android 应用程序抛出 IOException:发现冗余长度字节

Signing android app throws IOException: Redundant length bytes found

我们正在开发 Cordova 应用程序,但在签署 Android 版本的应用程序时遇到困难。

使用命令

jarsigner -keystore keystore.p12 -storetype pkcs12 android-release-unsigned.apk 1

给出以下异常

java.io.IOException: DerInputStream.getLength(): Redundant length bytes found

来自 this line in OpenJDK apparently this was added to fix CVE-2016-5546 虽然我对加密的了解还不够,无法真正理解它。

使用 openssl 导出证书并从中创建新的 p12 工作正常,但更改了签名,这意味着 play 商店拒绝上传。

我们的密钥库来自我们最初将应用程序开发外包给的另一家公司。

任何 jarsigner 或 keytool 命令都会抛出相同的异常,我认为这是有道理的,因为它们都使用相同的 Java lib

我们遇到了同样的问题。我们发现 JDK 1.8.0_112 没有您所说的错误。于是我们就这样解决了问题:

起初我们使用以下命令将temp_keystore.p12转换为mycert.keystore(Java\jdk1.8.0_112\bin\keytool.exe):

keytool -importkeystore -srckeystore temp_keystore.p12 -destkeystore mycert.keystore -srcstoretype pkcs12

然后我们使用下面的命令(Java\jdk1.8.0_112\bin\jarsigner.exe):

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore mycert.keystore ReadyForSigning.apk 1

签署apk。 (命令末尾的“1”为别名)

PS.: 可能不需要从 .p12 转换为 .keystore

我花了几个小时来寻找这个问题的解决方案。尝试了五个不同的 JDKs,但没有任何效果。我有一个非常流行的 playstore 应用程序的旧 PKCS12 证书,我从以前的开发人员那里“继承”了它,JDK 8 + 9 不会使用它。 Olexandr 的解决方案也没有帮助。

最后,几乎是侥幸,我在 Weijung Wang 的回复中找到了解决方案 here。它涉及使用 openssl 导出和重新导入证书。然后我在 JKS 密钥库中重新导入了 P12 密钥库,它现在可以与 JDK 8.

一起使用

引用:

weijun Weijun Wang added a comment - 2017-02-28 15:55
Openssl is able to remove the redundant 0s when extracting the private key. We can use the following 2 commands to normalize an affected pkcs12 file:

  1. openssl pkcs12 -in pkcs12-file -out key-and-cert -nodes -passin pass:abcXYZ

  2. openssl pkcs12 -in key-and-cert -export -out new-pkcs12-file -passout pass:abcXYZ

我一直有同样的错误,Olexandr 的解决方案不起作用,因为在 JDK8(更新 151)上使用 keytool 会在读取证书时引发错误,该证书是用 JDK7 生成的。 根据 Anders 的回答,使用 OpenSSL 可以使用(粘贴命令行以供将来参考):

openssl pkcs12 -in android.p12 -out android_fixed.cert -nodes -passin pass:your_p12_password
openssl pkcs12 -in android_fixed.cert -export -out android_cert.p12 -passout pass:your_p12_password

我有使用 JDK6 生成的密钥库。 作为解决方法,我一直在使用 JDK 1.8.0_112,方法是在 [项目结构] - [SDK 位置] - [JDK 位置] 下设置 JDK。

我已经通过以下步骤解决了问题(使用 macOS)。

使用 JDK 1.8.0_112

转换为 PKCS12
/Library/Java/JavaVirtualMachines/jdk1.8.0_112.jdk/Contents/Home/bin/keytool -importkeystore -srckeystore original.keystore -destkeystore 1.8.0_112.p12 -deststoretype PKCS12 -storepass ***** -destkeypass *****

使用 OpenSSL 进行处理(感谢 Weijung Wang 和 Anders Emil)

openssl pkcs12 -in 1.8.0_112.p12 -out 1.8.0_112.cert -nodes -passin pass:*****
openssl pkcs12 -in 1.8.0_112.cert -export -out 1.8.0_112.export.p12 -passout pass:*****

使用 JDK 1.8.0_161.

转换为 JKS

这里我需要指定-destkeypass、-srcalias和-destalias。 注意openSSL命令后别名是“1”,所以需要设置别名。

/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home/bin/keytool -importkeystore -srckeystore 1.8.0_112.export.p12 -srcstoretype pkcs12 -destkeystore 1.8.0_112.keystore -deststoretype jks -deststorepass ***** -destkeypass ***** -srcalias 1 -destalias youralias

所以指纹的结果是这样的

Original keystore:
     SHA1: 6C:9E:...:C5:8A

Original apk:
     SHA1: DA:4C:...:3F:02

Modified keystore:
     SHA1: C8:4A:...:2A:23

Modified apk:
     SHA1: DA:4C:...:3F:02

@Water 的解决方案对我不起作用。生成的 apk 的签名与原始的不同。

我终于通过上传使用 pepk 工具生成的私钥升级到 Google 的新应用程序签名来让它工作,并请求他们的支持重置上传密钥。

我找到了一个很棒的解决方案

因此,我也手动签署了我的 APK,但现在 Google 要求 targetSDK=30,它也要求使用 V2 签名方案。这是我不知道如何手动完成的事情。

但我找到了修复方法!

只需在文件 -> 项目结构 -> JDK 位置中将 Android Studio 使用的 JDK 设置为稍旧的内容。默认情况下,它使用其嵌入的 JDK 但您可以将其指向任何内容。例如,我使用 1.8.0_45。我现在可以再次直接使用旧的“损坏的”密钥库直接使用构建 -> 生成签名的 APK!

有一天 Android Studio 可能再次需要最新的“错误”JDK,但现在我已经准备好了。