484

我的 java 程序打包在一个 jar 文件中,并使用了一个外部 jar 库bouncy castle。我的代码编译得很好,但是运行 jar 会导致以下错误:

线程“main”中的异常 java.lang.SecurityException:Manifest 主要属性的签名文件摘要无效

我已经用谷歌搜索了一个多小时来寻找解释,但发现几乎没有价值。如果有人以前见过这个错误并且可以提供一些帮助,我将不胜感激。

4

22 回答 22

1165

对于那些在尝试使用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>
于 2011-07-19T07:25:24.960 回答
148

对于那些使用 gradle 并尝试创建和使用 fat jar 的人来说,以下语法可能会有所帮助。

jar {
    doFirst {
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
}
于 2013-01-21T15:15:29.067 回答
68

请使用以下命令

zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*.DSA'
于 2016-06-09T17:03:13.947 回答
62

您的一些依赖项可能是签名的 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 元素应该防止将来有修改日期的文件出错

我在链接线程中发现的其他变体对我不起作用。

于 2011-12-14T01:09:35.477 回答
48

此处列出的解决方案可能会提供一个指针。

Manifest 主要属性的签名文件摘要无效

底线:

最好保持官方 jar 原样,并将其作为依赖项添加到应用程序 jar 文件的清单文件中。

于 2009-06-16T04:09:27.233 回答
26

我在使用 IntelliJ IDEA 14.01 时遇到了这个问题。

我能够通过以下方式修复它:

File->Project Structure->Add New (Artifacts)->jar->From Modules With Dependencies on Create Jar From Module 窗口:

选择你的主要课程

来自库的 JAR 文件 选择复制到输出目录并通过清单链接

于 2014-12-11T18:07:46.340 回答
25

安全性已经是一个棘手的话题,但我很失望地看到最流行的解决方案是删除安全签名。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 证书。

于 2017-09-02T14:31:55.837 回答
18

我遇到了同样的问题,在某处参考后,它的工作方式如下更改:

<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>
于 2019-03-12T10:13:44.260 回答
8

假设您使用 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>
于 2010-09-05T07:02:07.663 回答
6

我最近开始在我的项目中使用 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 相关的文件有关。

于 2018-06-09T04:50:22.323 回答
4

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'
    }
}
于 2019-01-16T15:34:59.447 回答
3

如果您使用的是 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
}
于 2018-05-11T14:27:37.757 回答
2

将新 jar 中的 META-INF 文件夹与旧 jar 进行比较(在添加新库之前)。可能会有新文件。如果是,您可以删除它们。它应该有帮助。问候, 999michal

于 2010-06-02T14:12:59.993 回答
2

一种策略是使用 ANT 来简化从每个 Jar 文件中删除签名的过程。它将继续执行以下步骤:

  1. 将 MANIFEST.MF 复制到临时文件中
  2. 从临时文件中删除名称SHA条目
  3. 使用临时清单创建临时 Jar 文件
  4. 删除临时清单
  5. 将原始 Jar 文件与临时 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>
于 2016-08-08T11:28:15.163 回答
2

错误:发生 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->选择主类->选择“复制到输出目录并通过清单链接”->确定->应用->构建- > 构建工件... -> 构建

于 2017-02-11T09:16:14.633 回答
1

两个不同的签名者可能会混淆 Java 思维。

尝试从 jar 中删除 META-INF 文件夹,添加清单并再次签署 JAR,它帮助了我:http: //jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-属性/

于 2013-12-13T07:09:20.903 回答
1

如果您正在寻找一个 Fat JAR 解决方案,而无需解包或篡改原始库,而是使用特殊的 JAR 类加载器,请在此处查看我的项目

免责声明:我没有编写代码,只是将其打包并发布到 Maven Central 并在我的自述文件中描述如何使用它。

我个人使用它来创建包含 BouncyCastle 依赖项的可运行 uber JAR。也许它对你也有用。

于 2018-08-04T11:43:02.383 回答
0

对于那些对接受的解决方案有疑问的人,还有另一种方法可以使用 DontIncludeResourceTransformer 从阴影 jar 中排除资源:

https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#DontIncludeResourceTransformer

          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
                <resource>BC1024KE.DSA</resource>
            </transformer>
          </transformers>

从 Shade 3.0 开始,此转换器接受资源列表。在此之前,您只需要使用多个变压器,每个变压器都有一个资源。

于 2019-09-09T06:30:42.153 回答
0

当 Intellij 说“找到非托管 pom 文件”时,我在 Intellij 中单击“添加为 Maven 项目”时发生了这种情况。同时out文件夹已经生成。所以它没有得到最近的变化。

删除文件夹并运行程序为我解决了这个问题。然后重新创建了 out 文件夹。

也见小狐狸的回答。我收到的错误与他的非常相似。

于 2020-01-15T08:14:52.370 回答
0

您可以使用Shadow生成一个 jar。

Shadow 是一个 Gradle 插件,用于将项目的依赖类和资源组合到单个输出 Jar 中。组合的 Jar 通常被称为 fat-jar 或 uber-jar。

  1. 调整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)
    
  2. 执行命令gradle build,生成jar文件:

    • <项目目录>/build/libs/baseName-1.0-classifier.jar
于 2021-04-11T13:31:04.803 回答
-1

我有一个类似的问题。原因是我使用的 JDK 与我的 Windows 框中的默认 JRE 不同。

使用正确的 java.exe 解决了我的问题。

于 2010-08-02T12:54:36.997 回答
-3

如果您在尝试为 Xamarin.Android 绑定项目绑定 JAR 文件时遇到此问题,如下所示:

JATOXML:警告 J2XA006:在反映 com.your.class 时引发了缺少类错误:Manifest 主要属性的签名文件摘要无效

只需使用 Winzip 打开 JAR 文件并删除 meta-inf 目录。重建 - 工作完成

于 2014-09-23T09:30:06.017 回答