我怎么取消一个罐子?

时间:2011-10-13 16:09:20

标签: java jar jar-signing

有没有办法取消签名java jar文件?我有一些我正在尝试在我的开发环境中使用的签名罐子,但我得到安全例外,所以我想取消签名这些罐子,我可以在以后准备部署时签名。

7 个答案:

答案 0 :(得分:26)

我不知道答案,但这就是我要做的事情:

  1. 解压缩有问题的jar文件(jar只是拉链)
  2. 在META-INF目录中查找非MANIFEST-MF的内容。
  3. 删除那些东西。
  4. 打开MANIFEST-MF并删除看起来与签名相关的内容。
  5. rejar。

答案 1 :(得分:13)

要从jar文件中删除签名,请从中删除META-INF目录。 jar文件是一个zip文件,所以在Linux上你可以这样做:

zip -d file.jar 'META-INF/*.SF' 'META-INF/*.RSA'

如果您有许多要保存的jar文件,则以下命令会对当前目录及其下的每个jar文件执行此操作:

find . -name '*.jar' -exec zip -d '{}' 'META-INF/*.SF' 'META-INF/*.RSA' ';'

答案 2 :(得分:7)

我看到答案已被接受,但我认为无论如何这可能是有用的:

我已经做了一些事情(部分来自其他帖子)以使任务自动化 附带没有任何保证,但它适用于我:) 删除签名信息时复制Jar文件 注意,MANIFEST只留下MAIN部分!

使用javac JarUnsigner.java创建.class文件
使用java -cp <class dir> JarUnsigner <inJar> <outJar>

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class JarUnsigner {

  private static final String MANIFEST = "META-INF/MANIFEST.MF";

  public static void main(String[] args){

    if (args.length!=2){
      System.out.println("Arguments: <infile.jar> <outfile.jar>");
      System.exit(1);
    }
    String infile = args[0];
    String outfile = args[1];
    if ((new File(outfile)).exists()){
      System.out.println("Output file already exists:" + outfile);
      System.exit(1);
    }
    try{
      ZipFile zipFile = new ZipFile(infile);
      final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outfile));
      for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
        ZipEntry entryIn = (ZipEntry) e.nextElement();

        if (! exclude_file( entryIn.getName() ) ) {

          /* copy the entry as-is */
          zos.putNextEntry( new ZipEntry( entryIn.getName() ));
          InputStream is = zipFile.getInputStream(entryIn);
          byte[] buf = new byte[1024];
          int len;
          while ((len = (is.read(buf))) > 0) {
            zos.write(buf, 0, len);
          }
          zos.closeEntry();

        } else {

          if (MANIFEST.equals(entryIn.getName())){
            /* if MANIFEST, adjust the entry */
            zos.putNextEntry(new ZipEntry(MANIFEST));

            // manifest entries until first empty line. i.e. the 'MainAttributes' section
            // (this method is used so to keep the formatting exactly the same)
            InputStream mIS = zipFile.getInputStream(entryIn);
            BufferedReader in = new BufferedReader(new InputStreamReader(mIS));
            String line = in.readLine();
            byte[] mNL = "\n".getBytes("UTF-8");
            while( line != null && !line.trim().isEmpty() ) {
              zos.write( line.getBytes("UTF-8"));
              zos.write( mNL );
              line = in.readLine();
            }
            zos.write( mNL );
            zos.closeEntry();

          }else{
            /* else: Leave out the Signature files */
          }

        }

      }
      zos.close();
      System.out.println("Successfully unsigned " + outfile);

    }catch(IOException ex){
      System.err.println("Error for file: " + infile);
      ex.printStackTrace();
      System.exit(1);
    }
  }

  /**
   * Exclude .SF signature file
   * Exclude .RSA and DSA (signed version of .SF file) 
   * Exclude SIG-  files  (unknown sign types for signed .SF file)
   * Exclude Manifest file
   * @param filename
   * @return 
   */
  public static boolean exclude_file(String filename){
    return filename.equals("META-INF/MANIFEST.MF") ||
           filename.startsWith("META-INF/SIG-") || 
           filename.startsWith("META-INF/") && ( filename.endsWith(".SF") || filename.endsWith(".RSA") || filename.endsWith(".DSA") );
  }

}

在ANT中用于取消一堆罐子,如下所示:

<apply executable="java" dest="${output-dir}"> 
  <arg value="-cp" />
  <arg value="${dev-dir}" />
  <arg value="JarUnsigner" />
  <srcfile/> 
  <targetfile/>
  <fileset dir="${input-dir}" includes="*.jar"/> 
  <mapper type="glob" from="*.jar" to="*.jar"/> <!-- uses "dest"-->
</apply> 

答案 3 :(得分:1)

我通过小修改成功验证了DwB的答案:正如Is there a quick way to delete a file from a Jar / war without having to extract the jar and recreate it?所述,只能从jar工具中删除。我需要对专有构建脚本进行微小的改动,而我并不想重新调整整个jar。

当我将重要的.RSA文件设为零大小时,我意识到无法签名。这只能通过jar u命令完成:

cd %JAR_DIR%
jar xvf myapp.jar META-INF/MYAPP.RSA
type nul > META-INF/MYAPP.RSA
jar uvf myapp.jar META-INF/MYAPP.RSA
rmdir /S/Q META-INF

答案 4 :(得分:0)

如果罐子是由您开发的,那么它们可以被信任,您可能不需要签名。但是,如果您从外部获取它们,则应在使用它们之前调查安全性异常的原因。

答案 5 :(得分:0)

如果您查看jarsigner工具及其功能,它会生成3件事: 1).SF文件(签名文件) 2)基于所使用的算法的签名块文件(例如.RSA,.DSA等) 3)修改或创建MANIFEST.MF文件

要点: To&#34;取消一个罐子&#34;只需删除前两个文件(.sf和.dsa / rsa FILE)。 删除MANIFEST.MF文件,或打开它并删除列出的每个.class和其他文件列出的所有哈希值。

因此,如果删除META-INF目录中的所有内容,则存在删除可能需要的jar的其他资源(即属性文件等)的风险。这种&#34;霰弹枪方法&#34;删除&#34;看起来与签名有关的所有内容&#34;是有害的,并不遵循以下原则:第一不伤害(对你的.jar)。

见这里: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jarsigner.html

https://docs.oracle.com/javase/tutorial/deployment/jar/intro.html

了解签名和验证

&#34; ...当您签署JAR文件时,您的公钥将与相关证书一起放在存档中,以便任何想要验证签名的人都可以轻松使用它! 。 摘要和签名文件

当您签署JAR文件时,存档中的每个文件都会在存档的清单中被提供一个摘要条目。以下是此类条目的示例:

名称:test / classes / ClassOne.class SHA1-Digest:TD1GZt8G11dXY2p4olSZPc5Rj64 =

签名JAR文件时,会自动生成签名文件并将其放在JAR文件的META-INF目录中,该目录包含存档的清单。签名文件的文件名扩展名为.SF。

签名栏文件

除签名文件外,签名JAR文件时,签名块文件会自动放置在META-INF目录中。与清单文件或签名文件不同,签名块文件不是人类可读的。

签名块文件包含验证所必需的两个元素:

使用签名者私钥生成的JAR文件的数字签名 包含签名者公钥的证书,供想要验证签名JAR文件的任何人使用 签名块文件名通常具有.DSA扩展名,表示它们是由默认数字签名算法创建的。如果使用与其他标准算法相关联的密钥进行签名,则可以使用其他文件扩展名。

答案 6 :(得分:0)

另一个变体,它也编辑 MANIFEST.MF,即删除第一个空行中的所有内容(将 'jarlocation' 和 'signer' 部分编辑到您的案例中):

Tmpdir=tmp.$$
mkdir -p "$Tmpdir"
cd "$Tmpdir"
for i in <jarlocation>/*.jar; do \
    printf 'Doing %s\n' "$i"
    unzip "$i" 'META-INF/*'
    sed -i '/^[[:space:]]*$/,$d' META-INF/MANIFEST.MF
    zip -r "$i" META-INF/MANIFEST.MF
    test -f META-INF/<signer>.SF && zip -d "$i" 'META-INF/<signer>.*'
    rm -rf META-INF
done
cd ..
rm -rf "$Tmpdir"
printf 'Unsigning finished\n'