关于java:尝试运行.jar时出现“无效的签名文件”

“Invalid signature file” when attempting to run a .jar

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

线程"main"java.lang.securityException中出现异常:清单主属性的签名文件摘要无效

我在谷歌上搜索了一个多小时,想找到一个解释,却发现价值很低。如果有人以前看到过这个错误,并能提供一些帮助,我会很感激的。


对于那些在使用maven-shade-plugin创建uber jar时出现此错误的用户,解决方案是通过在插件配置中添加以下行来排除清单签名文件:

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
java.security.NoSuchProviderException: JCE cannot authenticate the provider BC

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文件中删除签名的过程。它将继续执行以下步骤:

  • 在临时文件中复制manifest.mf
  • 从临时文件中删除名称和SHA项
  • 使用临时清单创建临时JAR文件
  • 正在删除临时清单
  • 将原始JAR文件与临时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依赖项。也许它对你也很有用。


    我在gradlegroovy中也有同样的问题,我通过更新build.gradle文件并添加以下脚本来解决。

    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目录。重建-作业完成