"Неверный файл подписи" при попытке запустить.jar
Моя java-программа упакована в jar-файл и использует внешнюю jar-библиотеку http://www.bouncycastle.org/. Мой код компилируется нормально, но запуск jar приводит к следующей ошибке:
Исключение в потоке "main" java.lang.SecurityException: неверный дайджест файла подписи для основных атрибутов манифеста
Я более часа гуглял в поисках объяснения и нашел очень мало пользы. Если бы кто-то видел эту ошибку раньше и мог бы предложить некоторую помощь, я был бы обязан.
24 ответа
Решение, перечисленное здесь, может предоставить указатель.
Неверный дайджест файла подписи для основных атрибутов манифеста
Нижняя линия:
Вероятно, лучше оставить официальный jar как есть и просто добавить его в качестве зависимости в файле манифеста для вашего 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>
Для тех, кто использует gradle и пытается создать и использовать толстый 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/*SF'
Некоторые из ваших зависимостей, вероятно, являются подписанными jarfiles. Когда вы объединяете их в один большой jar-файл, соответствующие файлы сигнатур по-прежнему присутствуют и больше не соответствуют "большому комбинированному" jar-файлу, поэтому среда выполнения останавливается, думая, что файл jar был подделан (что... говорить).
Вы можете решить эту проблему, удалив файлы сигнатур из ваших зависимостей jarfile. К сожалению, это невозможно сделать за один шаг в муравье.
Тем не менее, я смог получить эту работу с 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>
Предполагается, что спящий элемент предотвращает ошибки в файлах с датами изменения в будущем.
Другие варианты, которые я нашел в связанных темах, не работали для меня.
Безопасность - это уже сложная тема, но я разочарован тем, что самым популярным решением является удаление сигнатур безопасности. JCE требует эти подписи. Maven shade использует файл Jar BouncyCastle, который помещает подписи в META-INF, но подписи BouncyCastle недопустимы для нового uber-jar (только для jar BC), и именно это приводит к ошибке недопустимой подписи в этом потоке,
Да, исключение или удаление подписей в соответствии с предложением @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.
У меня была эта проблема при использовании IntelliJ IDEA 14.01.
Я смог это исправить:
Файл-> Структура проекта-> Добавить новый (Артефакты)->jar-> Из модулей с зависимостями в окне Создать Jar из модуля:
Выберите свой основной класс
Файл JAR из библиотек. Выберите копию в выходной каталог и ссылку через манифест.
Я столкнулся с той же проблемой, после ссылки где-то это работало, как показано ниже:
<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>
Предполагая, что вы создаете свой jar-файл с помощью ant, вы можете просто дать команду 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>
Я недавно начал использовать IntelliJ в своих проектах. Тем не менее, некоторые из моих коллег все еще используют Eclipse в тех же проектах. Сегодня я получил ту же ошибку после выполнения jar-файла, созданного моим IntelliJ. В то время как все решения, о которых здесь говорится, говорят об одном и том же, ни одно из них не сработало для меня легко (возможно, из-за того, что я не использую ANT, сборка maven вызвала у меня другие ошибки, которые привели меня к http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException, а также я не мог понять, что такое подписанные банки самостоятельно!)
Наконец, это помогло мне
zip -d demoSampler.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*SF'
Угадай, что было удалено из моего фляги?!
deleting: META-INF/ECLIPSE_.SF
deleting: META-INF/ECLIPSE_.RSA
Кажется, что проблема была связана с некоторыми файлами, относящимися к затмению.
У меня была такая же проблема в gradle
а также groovy
Я исправил, обновив 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
}
Ошибка: произошла ошибка JNI, проверьте вашу установку и попробуйте снова. Исключение в потоке "main" java.lang.SecurityException: недопустимый дайджест файла подписи для основных атрибутов манифеста в sun.security.util.SignatureFileVerifier.processImpl(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:228) в java.util.jar.JarFile.initializeVerifier(JarFile.java:383) в java.util.jar.JarFile.getInputStream(JarFile.java:450) в sun.misc.URLClassPath$JarLoader$2.getInputStath (UR.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) в java.security.AccessController.doPrivileged(собственный метод) в java.net.URLClassLoader.findClass(URLClassLoader.java:361) в java.lang.ClassLoader.loadClass(ClassLoader:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) в java.lang.ClassLoader.loadClass(ClassLoader.java:357) в sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper))
Что мне помогло (IntelliJ IDEA 2016.3): Файл -> Структура проекта -> Артефакты -> Добавить JAR -> Выбрать основной класс -> Выбрать "скопировать в выходной каталог и связать через манифест" -> ОК -> Применить -> Построить - > Построить Артефакты... -> Построить
Сравните папку META-INF в новом jar со старым jar (до того, как вы добавили новые библиотеки). Возможно, что появятся новые файлы. Если да, вы можете удалить их. Это должно помочь. С уважением, 999michal
Стратегия будет заключаться в использовании ANT для упрощения удаления подписи из каждого файла Jar. Было бы выполнить следующие шаги:
- Копирование MANIFEST.MF во временный файл
- Удаление записей Name и SHA из временного файла
- Создание временного файла 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>
Вполне возможно, что два разных подписчика испортили разум Java.
Попробуйте удалить папку META-INF из jar, добавить манифест и снова подписать JAR, это мне помогло: http://jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-attributes/
Вы можете использовать Shadow для создания банки.
Shadow - это плагин Gradle для объединения классов зависимостей и ресурсов проекта в один выходной файл 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:- <Каталог проекта> /build/libs/baseName-1.0-classifier.jar
Если вы ищете решение Fat JAR без распаковки или изменения оригинальных библиотек, но со специальным загрузчиком классов JAR, взгляните на мой проект здесь.
Отказ от ответственности: я не писал код, просто упаковал его и опубликовал в Maven Central и описал в моем read-me, как его использовать.
Я лично использую его для создания исполняемых UAR-JAR-файлов, содержащих зависимости BouncyCastle. Может быть, это тоже полезно для вас.
Для тех, кто использует скрипт kotlin (kts) в качестве скрипта сборки:
task("fatJar", type = Jar::class) {
baseName = "${project.name}-fat"
manifest {
attributes["Implementation-Title"] = "Watcher Jar File"
attributes["Implementation-Version"] = version
attributes["Main-Class"] = "MainKt"
}
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) {
exclude(listOf("META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"))
}
with(tasks.jar.get() as CopySpec)
}
Для тех, у кого есть проблемы с принятым решением, есть другой способ исключить ресурс из затененной банки с помощью DontIncludeResourceTransformer:
https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>BC1024KE.DSA</resource>
</transformer>
</transformers>
Начиная с Shade 3.0, этот преобразователь принимает список ресурсов. Перед этим вам просто нужно использовать несколько трансформаторов, каждый с одним ресурсом.
Это случилось со мной в Intellij, когда я щелкнул "Добавить как проект Maven" в нижней строке, когда Intellij сказал "найдены неуправляемые файлы pom". Между тем наша папка уже была создана. Таким образом, он не получил последних изменений.
Удаление папки и запуск программы решили проблему для меня. Затем была воссоздана папка out.
См. Также ответ Литтл Фокс. Ошибка, которую я получил, была очень похожа на его.
Как упоминал @MattW, выполнение этого для поставщика JCE (например, BouncyCastle) может привести к возникновению новых исключений.
В любом случае, если вы хотите исправить ошибку, упомянутую в ОП, и используете сценарий сборки Gradle Kotlin, вы можете использовать следующий код, чтобы он работал:
tasks.withType<Jar> {
excludes += listOf("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
}
Это исключит список файлов из задач с типом «Jar», независимо от того, какие это задачи.
У меня была похожая проблема. Причиной было то, что я компилировал с использованием JDK с другим JRE, чем по умолчанию в моем окне Windows.
Использование правильного java.exe решило мою проблему.
Если вы получаете это при попытке связать файлы JAR для проекта привязок Xamarin.Android, например:
JARTOXML: предупреждение J2XA006: ошибка отсутствующего класса возникла при отражении com.your.class: неверный дайджест файла подписи для основных атрибутов манифеста
Просто откройте JAR-файлы с помощью Winzip и удалите каталоги meta-inf. Перестроить - работа выполнена