尝试运行.jar时“无效的签名文件”

时间:2009-06-16 03:49:52

标签: java jar executable-jar

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

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

我用谷歌搜索了一个多小时寻找解释并发现很少有价值。如果有人以前看过这个错误并且可以提供一些帮助,我将不得不承担责任。

21 个答案:

答案 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)

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

  

Invalid signature file digest for Manifest main attributes

底线:

  

最好保留官方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文件中删除签名。它将继续以下步骤:

  1. 在临时文件中复制MANIFEST.MF
  2. 从临时文件中删除名称 SHA 条目
  3. 使用临时清单
  4. 创建临时Jar文件
  5. 删除临时清单
  6. 将原始Jar文件与临时文件交换
  7. 以下是执行工作的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从阴影罐中排除资源:

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开始,此转换器接受资源列表。在此之前,您只需要使用多个变压器,每个变压器只有一种资源。

答案 16 :(得分:0)

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

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

也请参阅Little Fox的答案。我收到的错误与他的错误非常相似。

答案 17 :(得分: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

答案 18 :(得分:-1)

如果您在尝试绑定Xamarin.Android绑定项目的JAR文件时遇到此问题,那么:

  

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

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

答案 19 :(得分:-1)

我通过更新gradle文件并添加以下脚本来解决在groovybuild.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解决了我的问题。