java - 试图运行.jar时出现“签名文件无效”




executable-jar (10)

错误:发生了JNI错误,请检查您的安装并再次尝试线程“main”中的异常java.lang.SecurityException:在sun.security.util.SignatureFileVerifier.processImpl上的Manifest主要属性的无效签名文件摘要(SignatureFileVerifier.java: 314)在java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)上的sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268)位于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) java.net.URLClassLoader.access $ 100(URLClassLoader.java:73)在java.net.URLClassLoader $ 1.run(URLClassLoader.java:368)at java.net.URLClassLoade 在java.net.URLClassLoader.findClass(URLClassLoader.java:361)上java.lang.ClassLoader.loadClass(ClassLoader.java)处的java.security.AccessController.doPrivileged(Native方法)处的r $ 1.run(URLClassLoader.java:362) :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 - >选择主类 - >选择“复制到输出目录并通过清单链接” - >确定 - >应用 - >生成 - >构建工件... - >构建

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

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

我搜索了一个多小时的搜索解释,发现价值很小。 如果有人曾经看到过这个错误,并可以提供一些帮助,我会被迫。


一种策略是使用ANT来简化从每个Jar文件中删除签名。 它将按照以下步骤进行:

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

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

我能够通过以下方式解决它:

文件 - >项目结构 - >添加新(工件) - > jar->从模块创建Jar从模块窗口依赖的模块:

选择你主要的课程

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


假设你用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>

安全性已经是一个棘手的话题,但我很失望看到最流行的解决方案是删除安全签名。 JCE需要这些签名 。 Maven遮罩爆炸BouncyCastle jar文件,将签名放入META-INF中,但BouncyCastle签名对于新的超级jar(仅用于BC jar) 无效,这就是导致此线程中的无效签名错误的原因

是的,排除或删除@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方法在单个可执行的jar中保留BouncyCastle签名

更新

另一种做法(正确方法)是使用Maven Jar签名者 。 这使您可以继续使用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证书。


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

jar {
    doFirst {
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
}

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

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



这里列出的解决方案可能提供一个指针。

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

底线:

将官方jar保留原样并将其作为应用程序jar文件的清单文件中的依赖项添加可能是最好的选择。


对于那些在尝试使用maven-shade-plugin创建uber-jar时出现此错误的解决方案是,通过将以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>




executable-jar