我的java程序打包在一个jar文件中,并使用外部jar库bouncy castle。我的代码编译得很好,但运行jar会导致以下错误:
线程“main”中的异常java.lang.SecurityException:Manifest主要属性的签名文件摘要无效
我用谷歌搜索了一个多小时寻找解释并发现很少有价值。如果有人以前看过这个错误并且可以提供一些帮助,我将不得不承担责任。
答案 0 :(得分:995)
对于在尝试使用maven-shade-plugin
创建uber-jar时遇到此错误的用户,解决方案是通过在插件配置中添加以下行来排除清单签名文件:
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<!-- Additional configuration. -->
</configuration>
答案 1 :(得分:123)
对于那些使用gradle并尝试创建和使用fat jar的人,以下语法可能有所帮助。
jar {
doFirst {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
答案 2 :(得分:55)
您的某些依赖项可能是已签名的jar文件。当你将它们全部组合成一个大的jar文件时,相应的签名文件仍然存在,并且不再匹配“大组合”jar文件,因此运行时停止认为jar文件已经被篡改(它...已经如此... 。说话)
您可以通过从jarfile依赖项中删除签名文件来解决问题。不幸的是,it's not possible to do this in one step in ant。
但是,我能够通过两个步骤使用Ant,而无需通过使用以下方式专门命名每个jarfile依赖项:
<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>
<attribute name="Main-Class" value="com.mycompany.MyMain" />
</manifest>
</jar>
</target>
睡眠元素应该阻止errors about files with modification dates in the future。
我在链接线程中找到的其他变体对我不起作用。
答案 3 :(得分:45)
此处列出的解决方案可能会提供指针。
底线:
最好保留官方jar 并且只是将它作为依赖项添加到您的清单文件中 应用程序jar文件。
答案 4 :(得分:45)
请使用以下命令
zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF'
答案 5 :(得分:25)
使用IntelliJ IDEA 14.01时出现此问题。
我能够解决它:
文件 - &gt;项目结构 - &gt;添加新(工件) - &gt; jar-&gt;来自模块窗口创建Jar的具有依赖关系的模块:
选择您的主要课程
来自图书馆的JAR文件 选择复制到输出目录并通过清单
链接答案 6 :(得分:13)
安全性已经是一个棘手的话题,但我很失望地看到最流行的解决方案是删除安全签名。 JCE requires these signatures。 Maven阴影爆炸了BouncyCastle jar文件,该文件将签名放入META-INF,但BouncyCastle签名对于新的超级jar(仅适用于BC jar)无效,并且那个&#39; s是什么导致此帖子中的无效签名错误。
是的,排除或删除@ruhsuzbaykus建议的签名确实会使原始错误消失,但它也会导致新的,神秘的错误:
java.security.NoSuchAlgorithmException: PBEWithSHA256And256BitAES-CBC-BC SecretKeyFactory not available
通过明确指定在哪里找到算法:
SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC","BC");
我能够得到一个不同的错误:
java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
JCE无法对提供商进行身份验证,因为我们已删除了加密签名 by following the suggestion elsewhere in this same thread。
我找到的解决方案是executable packer插件,该插件使用jar-in-jar方法在单个可执行jar中保留BouncyCastle签名。
另一种方法(正确的方法?)是使用Maven Jar signer。这使您可以继续使用Maven阴影而不会出现安全错误。但是,您必须拥有代码签名证书(Oracle建议搜索&#34; Java代码签名证书&#34;)。 POM配置如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>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>
<artifactId>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>
<alias>myfirstkey</alias>
<storepass>111111</storepass>
<keypass>111111</keypass>
</configuration>
</plugin>
不,没有办法让JCE识别自签名证书,所以如果你需要保留BouncyCastle证书,你必须使用jar-in-jar插件或获得JCE证书。
答案 7 :(得分:8)
假设您使用ant构建jar文件,您可以指示ant省略META-INF目录。这是我的蚂蚁目标的简化版本:
<jar destfile="app.jar" basedir="${classes.dir}">
<zipfileset excludes="META-INF/**/*" src="${lib.dir}/bcprov-jdk16-145.jar"></zipfileset>
<manifest>
<attribute name="Main-Class" value="app.Main"/>
</manifest>
</jar>
答案 8 :(得分:3)
在遇到某处引用后,我遇到了同样的问题,它的工作方式如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>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>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
答案 9 :(得分:2)
将新jar中的文件夹META-INF与旧jar进行比较(在添加新库之前)。有可能会有新文件。如果是,您可以删除它们。它应该有帮助。 问候, 999michal
答案 10 :(得分:2)
我最近开始在我的项目中使用IntelliJ。但是,我的一些同事仍然在同一个项目中使用Eclipse。今天,执行IntelliJ创建的jar文件后,我得到了同样的错误。虽然这里的所有解决方案都谈论着几乎相同的事情,但它们中没有一个能够轻松地为我工作(可能是因为我没有使用ANT,maven构建给了我其他错误,这些错误将我引向http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException,并且我自己也无法弄清楚签名的罐子是什么!)
最后,this帮助了我
zip -d demoSampler.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF'
猜猜我的jar文件中删除了哪些内容?!
deleting: META-INF/ECLIPSE_.SF
deleting: META-INF/ECLIPSE_.RSA
似乎这个问题与一些与eclipse相关的文件有关。
答案 11 :(得分:2)
错误:发生了JNI错误,请检查您的安装并重试 线程&#34; main&#34;中的例外情况java.lang.SecurityException:Manifest主要属性的签名文件摘要无效 at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:314) at sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268) 在java.util.jar.JarVerifier.processEntry(JarVerifier.java:316) 在java.util.jar.JarVerifier.update(JarVerifier.java:228) 在java.util.jar.JarFile.initializeVerifier(JarFile.java:383) 在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) 在java.net.URLClassLoader.access $ 100(URLClassLoader.java:73) 在java.net.URLClassLoader $ 1.run(URLClassLoader.java:368) 在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): 档案 - &gt;项目结构 - &gt;文物 - &gt;添加JAR - &gt;选择主类 - &gt;选择&#34;复制到输出目录并通过清单&#34; - &GT;好的 - &gt;申请 - &gt;构建 - &gt;构建工件...... - &gt;构建
答案 12 :(得分:1)
策略包括使用ANT简化从每个Jar文件中删除签名。它将继续以下步骤:
以下是执行工作的ANT macrodef:
<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="\nName:(.+?)\nSH" 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任务中以这种方式调用该定义:
<target name="unsignJar">
<unsignjar jarFile="org.test.myjartounsign.jar" />
</target>
答案 13 :(得分:1)
两个不同的签名者有可能搞乱java思想。
尝试从jar中删除META-INF文件夹,添加清单并再次签署JAR,它帮助了我:http://jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-attributes/
答案 14 :(得分:1)
如果您要查找不解包或篡改原始库但使用特殊的JAR类加载器的Fat JAR解决方案,请查看my project here。
免责声明:我没有编写代码,只是打包并将其发布在Maven Central上,并在我的自述文件中描述了如何使用它。
我个人使用它来创建包含BouncyCastle依赖项的可运行uber JAR。也许对您也有用。
答案 15 :(得分:0)
对于那些对接受的解决方案有疑问的人,还有另一种方法是使用DontIncludeResourceTransformer从阴影罐中排除资源:
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>BC1024KE.DSA</resource>
</transformer>
</transformers>
从Shade 3.0开始,此转换器接受资源列表。在此之前,您只需要使用多个变压器,每个变压器只有一种资源。
答案 16 :(得分:0)
在Intellij中,当我单击底部的“添加为Maven项目”时,当Intellij说“找到了非托管pom文件”时,发生了这种情况。同时out文件夹已经生成。因此它没有得到最近的更改。
删除文件夹并运行程序为我解决了这个问题。然后重新创建出文件夹。
也请参阅Little Fox的答案。我收到的错误与他的错误非常相似。
答案 17 :(得分:0)
您可以使用 Shadow 生成一个 jar。
<块引用>Shadow 是一个 Gradle 插件,用于将项目的依赖类和资源组合到单个输出 Jar 中。组合的 Jar 通常被称为 fat-jar 或 uber-jar。
修改build.gradle
plugins {
...
// ① Add the shadow plugin
id "com.github.johnrengelman.shadow" version "5.2.0"
}
...
// ② Config the shadow jar, its name is baseName-1.0-classifier.jar
shadowJar {
archiveBaseName.set('baseName')
archiveClassifier.set('classifier')
archiveVersion.set('1.0')
manifest {
attributes 'Main-Class': 'Main'
}
}
// ③ Disable the default jar task
jar.enabled = false
// ④ Execute the shadowJar task when compiling
build.dependsOn(shadowJar)
执行命令gradle build
,会生成jar文件:
答案 18 :(得分:-1)
如果您在尝试绑定Xamarin.Android绑定项目的JAR文件时遇到此问题,那么:
JARTOXML:警告J2XA006:在反映com.your.class时出现了缺少的类错误:Manifest主要属性的签名文件摘要无效
使用Winzip打开JAR文件并删除meta-inf目录。重建 - 完成工作
答案 19 :(得分:-1)
我通过更新gradle
文件并添加以下脚本来解决在groovy
和build.gradle
中遇到的相同问题。
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'
}
}
答案 20 :(得分:-1)
我有类似的问题。原因是我使用的JDK编译的JRE与Windows框中的默认JRE不同。
使用正确的java.exe解决了我的问题。