我的 java 程序打包在一个 jar 文件中,并使用了一个外部 jar 库bouncy castle。我的代码编译得很好,但是运行 jar 会导致以下错误:
线程“main”中的异常 java.lang.SecurityException:Manifest 主要属性的签名文件摘要无效
我已经用谷歌搜索了一个多小时来寻找解释,但发现几乎没有价值。如果有人以前见过这个错误并且可以提供一些帮助,我将不胜感激。
我的 java 程序打包在一个 jar 文件中,并使用了一个外部 jar 库bouncy castle。我的代码编译得很好,但是运行 jar 会导致以下错误:
线程“main”中的异常 java.lang.SecurityException:Manifest 主要属性的签名文件摘要无效
我已经用谷歌搜索了一个多小时来寻找解释,但发现几乎没有价值。如果有人以前见过这个错误并且可以提供一些帮助,我将不胜感激。
对于那些在尝试使用maven-shade-plugin
.
<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>
对于那些使用 gradle 并尝试创建和使用 fat jar 的人来说,以下语法可能会有所帮助。
jar {
doFirst {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
请使用以下命令
zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*.DSA'
您的一些依赖项可能是签名的 jarfile。当您将它们全部组合成一个大 jarfile 时,相应的签名文件仍然存在,并且不再与“大组合”jarfile 匹配,因此运行时停止认为 jar 文件已被篡改(它......必须如此说话)。
假设您使用的是 ant,您可以通过从 jarfile 依赖项中消除签名文件来解决问题。不幸的是,在 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>
sleep 元素应该防止将来有修改日期的文件出错。
我在链接线程中发现的其他变体对我不起作用。
我在使用 IntelliJ IDEA 14.01 时遇到了这个问题。
我能够通过以下方式修复它:
File->Project Structure->Add New (Artifacts)->jar->From Modules With Dependencies on Create Jar From Module 窗口:
选择你的主要课程
来自库的 JAR 文件 选择复制到输出目录并通过清单链接
安全性已经是一个棘手的话题,但我很失望地看到最流行的解决方案是删除安全签名。JCE 需要这些签名。Maven 阴影会爆炸 BouncyCastle jar 文件,该文件将签名放入 META-INF,但 BouncyCastle 签名对于新的 uber-jar 无效(仅适用于 BC jar),这就是导致此线程中的 Invalid signature 错误的原因.
是的,按照@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 无法对提供者进行身份验证,因为我们已 按照同一线程中其他地方的建议删除了加密签名。
我找到的解决方案是可执行打包程序插件,它使用 jar-in-jar 方法将 BouncyCastle 签名保存在单个可执行 jar 中。
另一种方法(正确的方法?)是使用Maven Jar signer。这使您可以继续使用 Maven 阴影而不会出现安全错误。但是,您必须拥有代码签名证书(Oracle 建议搜索“Java 代码签名证书”)。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 证书。
我遇到了同样的问题,在某处参考后,它的工作方式如下更改:
<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>
假设您使用 ant 构建 jar 文件,您可以指示 ant 忽略 META-INF 目录。这是我的 ant 目标的简化版本:
<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>
我最近开始在我的项目中使用 IntelliJ。但是,我的一些同事仍然在相同的项目中使用 Eclipse。今天,在执行我的 IntelliJ 创建的 jar 文件后,我遇到了同样的错误。虽然这里的所有解决方案都在谈论几乎相同的事情,但没有一个对我很容易(可能是因为我不使用 ANT,maven build 给了我其他错误,这些错误让我参考了http://cwiki.apache.org/ confluence/display/MAVEN/MojoExecutionException,而且我自己也不知道签名的罐子是什么!)
最后,这对我有帮助
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 相关的文件有关。
gradle
我在创建胖 Jar 时遇到了同样的问题,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'
}
}
如果您使用的是 gradle,这里有一个完整的 farJar 任务:
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
}
将新 jar 中的 META-INF 文件夹与旧 jar 进行比较(在添加新库之前)。可能会有新文件。如果是,您可以删除它们。它应该有帮助。问候, 999michal
一种策略是使用 ANT 来简化从每个 Jar 文件中删除签名的过程。它将继续执行以下步骤:
这是一个ANT 宏定义:
<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>
错误:发生 JNI 错误,请检查您的安装并重试 线程“main”中的异常 java.lang.SecurityException:sun.security.util.SignatureFileVerifier.processImpl 的 Manifest 主要属性的签名文件摘要无效(SignatureFileVerifier.java: 314) 在 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.getInputStream(JarFile.java:450) 在 sun.misc.URLClassPath$JarLoader$2.getInputStream(URLClassPath) 的 java.util.jar.JarFile.initializeVerifier(JarFile.java:383) .java:977) 在 sun.misc.Resource.cachedInputStream(Resource.java:77) 在 sun.misc.Resource.getByteBuffer(Resource.java:160) 在 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) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.爪哇:495)在 java.net.URLClassLoader.findClass(URLClassLoader.java:361) 在 java.security.AccessController.doPrivileged(Native Method) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:362) 运行(URLClassLoader.java:368) ) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun .launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)在 java.net.URLClassLoader.findClass(URLClassLoader.java:361) 在 java.security.AccessController.doPrivileged(Native Method) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:362) 运行(URLClassLoader.java:368) ) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun .launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
对我有什么帮助(IntelliJ IDEA 2016.3):文件->项目结构->工件->添加JAR->选择主类->选择“复制到输出目录并通过清单链接”->确定->应用->构建- > 构建工件... -> 构建
两个不同的签名者可能会混淆 Java 思维。
尝试从 jar 中删除 META-INF 文件夹,添加清单并再次签署 JAR,它帮助了我:http: //jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-属性/
如果您正在寻找一个 Fat JAR 解决方案,而无需解包或篡改原始库,而是使用特殊的 JAR 类加载器,请在此处查看我的项目。
免责声明:我没有编写代码,只是将其打包并发布到 Maven Central 并在我的自述文件中描述如何使用它。
我个人使用它来创建包含 BouncyCastle 依赖项的可运行 uber JAR。也许它对你也有用。
对于那些对接受的解决方案有疑问的人,还有另一种方法可以使用 DontIncludeResourceTransformer 从阴影 jar 中排除资源:
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>BC1024KE.DSA</resource>
</transformer>
</transformers>
从 Shade 3.0 开始,此转换器接受资源列表。在此之前,您只需要使用多个变压器,每个变压器都有一个资源。
当 Intellij 说“找到非托管 pom 文件”时,我在 Intellij 中单击“添加为 Maven 项目”时发生了这种情况。同时out文件夹已经生成。所以它没有得到最近的变化。
删除文件夹并运行程序为我解决了这个问题。然后重新创建了 out 文件夹。
也见小狐狸的回答。我收到的错误与他的非常相似。
您可以使用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文件:
我有一个类似的问题。原因是我使用的 JDK 与我的 Windows 框中的默认 JRE 不同。
使用正确的 java.exe 解决了我的问题。
如果您在尝试为 Xamarin.Android 绑定项目绑定 JAR 文件时遇到此问题,如下所示:
JATOXML:警告 J2XA006:在反映 com.your.class 时引发了缺少类错误:Manifest 主要属性的签名文件摘要无效
只需使用 Winzip 打开 JAR 文件并删除 meta-inf 目录。重建 - 工作完成