“Invalid signature file” when attempting to run a .jar
我的Java程序打包在一个JAR文件中,并使用一个外部JAR库,Posiy城堡。我的代码编译得很好,但是运行jar会导致以下错误:
线程"main"java.lang.securityException中出现异常:清单主属性的签名文件摘要无效
我在谷歌上搜索了一个多小时,想找到一个解释,却发现价值很低。如果有人以前看到过这个错误,并能提供一些帮助,我会很感激的。
对于那些在使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | <configuration> <filters> <filter> *:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <!-- Additional configuration. --> </configuration> |
对于那些使用Gradle并试图创建和使用胖jar的用户,以下语法可能会有所帮助。
1 2 3 4 5 6 | jar { doFirst { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } } exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' } |
您的一些依赖项可能是已签名的JAR文件。当您将它们组合成一个大jar文件时,相应的签名文件仍然存在,并且不再与"大组合"jar文件匹配,因此运行时停止认为jar文件已被篡改(可以这么说…)。
您可以通过从JAR文件依赖项中删除签名文件来解决这个问题。不幸的是,在Ant中不可能一步完成这项工作。
但是,我可以通过以下两个步骤来使用Ant,而无需具体命名每个jarfile依赖项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <target name="jar" depends="compile" description="Create one big jarfile."> <jar jarfile="${output.dir}/deps.jar"> <zipgroupfileset dir="jars"> <include name="**/*.jar" /> </zipgroupfileset> </jar> <sleep seconds="1" /> <jar jarfile="${output.dir}/myjar.jar" basedir="${classes.dir}"> <zipfileset src="${output.dir}/deps.jar" excludes="META-INF/*.SF" /> <manifest> </manifest> </jar> </target> |
sleep元素应该可以防止将来修改日期的文件出错。
我在链接线程中发现的其他变体对我不起作用。
请使用以下命令
1 | zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF' |
这里列出的解决方案可能提供一个指针。
Invalid signature file digest for Manifest main attributes
底线:
It's probably best to keep the official jar as
is and just add it as a dependency in the manifest file for your
application jar file.
我在使用Intellij IDEA 14.01时遇到了这个问题。
我可以通过以下方式解决:
文件->项目结构->添加新的(工件)->jar->from modules with dependencies on the create jar from module window:
选择你的主班
来自库的JAR文件选择复制到输出目录并通过清单链接
安全性已经是一个棘手的话题,但我很失望看到最流行的解决方案是删除安全签名。JCE需要这些签名。maven shade爆炸了bouncycastle jar文件,该文件将签名放入META-INF,但bouncycastle签名对新的uber jar无效(仅对bc jar有效),这就是导致此线程中的无效签名错误的原因。
是的,排除或删除@ruhsuzbaykus建议的签名确实会使原始错误消失,但也可能导致新的、神秘的错误:
1 | java.security.NoSuchAlgorithmException: PBEWithSHA256And256BitAES-CBC-BC SecretKeyFactory not available |
通过显式指定在何处查找这样的算法:
1 | SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC","BC"); |
我得到了一个不同的错误:
1 |
JCE无法对提供者进行身份验证,因为我们已经按照同一线程中其他地方的建议删除了加密签名。
我找到的解决方案是可执行打包程序插件,它使用jar-in-jar方法在单个可执行jar中保留bouncycastle签名。
更新:另一种方法(正确的方法?)是使用maven jar签名者。这允许您继续使用maven shade,而不会出现安全错误。但是,您必须有一个代码签名证书(Oracle建议搜索"Java代码签名证书")。pom配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <plugin> <groupId>org.apache.maven.plugins</groupId> maven-shade-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter> org.bouncycastle:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>your.class.here</mainClass> </transformer> </transformers> <shadedArtifactAttached>true</shadedArtifactAttached> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> maven-jarsigner-plugin</artifactId> <version>1.4</version> <executions> <execution> <id>sign</id> <goals> <goal>sign</goal> </goals> </execution> <execution> <id>verify</id> <goals> <goal>verify</goal> </goals> </execution> </executions> <configuration> <keystore>/path/to/myKeystore</keystore> myfirstkey</alias> <storepass>111111</storepass> <keypass>111111</keypass> </configuration> </plugin> |
不,没有办法让JCE识别自签名证书,所以如果您需要保留bouncycastle证书,您必须使用jar-in-jar插件或获取JCE证书。
假设您使用Ant构建JAR文件,您可以指示Ant去掉META-INF目录。这是我的Ant目标的简化版本:
1 2 3 4 5 6 | <jar destfile="app.jar" basedir="${classes.dir}"> <zipfileset excludes="META-INF/**/*" src="${lib.dir}/bcprov-jdk16-145.jar"></zipfileset> <manifest> </manifest> </jar> |
我也面临着同样的问题,在参考了某个地方之后,它的作用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <plugin> <groupId>org.apache.maven.plugins</groupId> maven-shade-plugin</artifactId> <version>3.2.1</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter> *:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> |
Error: A JNI error has occurred, please check your installation and try again
Exception in thread"main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:314)
at sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268)
at java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)
at java.util.jar.JarVerifier.update(JarVerifier.java:228)
at java.util.jar.JarFile.initializeVerifier(JarFile.java:383)
at java.util.jar.JarFile.getInputStream(JarFile.java:450)
at sun.misc.URLClassPath$JarLoader$2.getInputStream(URLClassPath.java:977)
at sun.misc.Resource.cachedInputStream(Resource.java:77)
at sun.misc.Resource.getByteBuffer(Resource.java:160)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:454)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
是什么帮助了我(Intellij IDEA 2016.3):文件->项目结构->工件->添加JAR->选择主类->选择"复制到输出目录并通过清单链接"-->OK->Apply->Build->Build工件…>建造
如果您正在使用Gradle,下面是完整的Farjar任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 | version = '1.0' //create a single Jar with all dependencies task fatJar(type: Jar) { manifest { attributes 'Implementation-Title': 'Gradle Jar File Example', 'Implementation-Version': version, 'Main-Class': 'com.example.main' } baseName = project.name + '-all' from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' with jar } |
我最近开始在我的项目中使用intellij。但是,我的一些同事仍然在同一个项目中使用Eclipse。今天,在执行我的intellij创建的jar文件之后,我遇到了同样的错误。虽然这里的所有解决方案都几乎是相同的,但它们都不容易对我起作用(可能是因为我不使用Ant,Maven Build给了我其他错误,这些错误将我引向http://cwiki.apache.org/confluence/display/maven/mojoexecutionexception,而且我也不知道自己签名的jar是什么!)
最后,这帮了我
1 | zip -d demoSampler.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF' |
猜猜从我的JAR文件中删除了什么?!
1 2 | deleting: META-INF/ECLIPSE_.SF deleting: META-INF/ECLIPSE_.RSA |
这个问题似乎与一些Eclipse相关的文件有关。
比较新JAR和旧JAR中的META-INF文件夹(在添加新库之前)。有可能会有新的文件。如果是,可以删除它们。这应该有帮助。当做,99 9MICHAL
一种策略是使用Ant来简化从每个JAR文件中删除签名的过程。它将继续执行以下步骤:
这是一个蚂蚁宏定义执行的工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <macrodef name="unsignjar" description="To unsign a specific Jar file"> <attribute name="jarfile" description="The jar file to unsign" /> <sequential> <!-- Copying to the temporary manifest file --> <copy toFile="@{jarFile}_MANIFEST.tmp"> <resources> <zipentry zipfile="@{jarFile}" name="META-INF/MANIFEST.MF"/> </resources> </copy> <!-- Removing the Name and SHA entries from the temporary file --> <replaceregexp file="@{jarFile}_MANIFEST.tmp" match=" Name:(.+?) SH" replace="SH" flags="gis" byline="false"/> <replaceregexp file="@{jarFile}_MANIFEST.tmp" match="SHA(.*)" replace="" flags="gis" byline="false"/> <!-- Creating a temporary Jar file with the temporary manifest --> <jar jarfile="@{jarFile}.tmp" manifest="@{jarFile}_MANIFEST.tmp"> <zipfileset src="@{jarFile}"> <include name="**"/> <exclude name="META-INF/*.SF"/> <exclude name="META-INF/*.DSA"/> <exclude name="META-INF/*.RSA"/> </zipfileset> </jar> <!-- Removing the temporary manifest --> <delete file="@{jarFile}_MANIFEST.tmp" /> <!-- Swapping the original Jar file with the temporary one --> <move file="@{jarFile}.tmp" tofile="@{jarFile}" overwrite="true" /> </sequential> |
`
然后可以在Ant任务中以这种方式调用定义:
1 2 3 | <target name="unsignJar"> <unsignjar jarFile="org.test.myjartounsign.jar" /> </target> |
这可能是两个不同的签名者搞乱了Java思维。
尝试从JAR中删除META-INF文件夹,再次添加清单并对JAR进行签名,这对我有帮助:http://jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-attributes/
如果您正在寻找一个不需要解包或篡改原始库的胖jar解决方案,而是使用一个特殊的jar类加载器,请看我的项目。
免责声明:我没有写代码,只是将它打包并发布在MavenCentral上,并在我的"阅读我"中描述如何使用它。
我个人使用它来创建可运行的uber jar,其中包含bouncycastle依赖项。也许它对你也很有用。
我在
1 2 3 4 5 6 7 8 9 10 11 | jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' manifest { attributes 'Main-Class': 'com.test.Main' } } |
我也有类似的问题。原因是我使用的JDK编译时使用的JRE与Windows框中的默认JRE不同。
使用正确的java.exe解决了我的问题。
如果您在尝试为xamarin.android绑定项目绑定JAR文件时遇到这种情况:
JARTOXML : warning J2XA006: missing class error was raised while reflecting com.your.class : Invalid signature file digest for Manifest main attributes
只需使用winzip打开JAR文件并删除META INF目录。重建-作业完成