使用keytool生成公钥私钥证书并且读取出来,使用私钥签名jar并验证(转)

Posted guoDaXia的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用keytool生成公钥私钥证书并且读取出来,使用私钥签名jar并验证(转)相关的知识,希望对你有一定的参考价值。

参考链接:http://happyqing.iteye.com/blog/2139504

    :https://blog.csdn.net/arjelarxfc/article/details/52461828

              :https://blog.csdn.net/yangxt/article/details/1796965

 

在看书的时候涉及到了Java的安全加密技术,然后发现生成私钥公钥证书用的是keytool这个jdk自带插件

 

keytool的主要用法:

keytool的几个常用的命令。

1.创建证书

2.查看证书库

3.导出证书文件

4.导入证书的信息

5.查看证书信息

6.删除密钥库中的条目

7.修改证书条目的口令

 

SUN公司提供了制作证书的工具keytool。

      在JDK 1.4以后的版本中都包含了这一工具,它的位置为<JAVA_HOME>\\bin\\keytool.exe。

 

 

1.创建证书

Cmd代码  
  1. keytool -genkeypair -alias "test1" -keyalg "RSA" -keystore "test.keystore"  

说明:

密钥库密码为testtest

证书条目密码为testtest1,若别名为test2则密码为testtest2

这样为个不乱

功能:

创建一个别名为test1的证书条目,该条目存放在名为test.keystore的密钥库中,若test.keystore密钥库不存在则创建。

参数说明:

-genkeypair:生成一对非对称密钥;

-alias:指定密钥对的别名,该别名是公开的;
-keyalg:指定加密算法,本例中的采用通用的RAS加密算法;

-keystore:密钥库的路径及名称,不指定的话,默认在操作系统的用户目录下生成一个".keystore"的文件

注意:

1.“名字与姓氏”应该是域名,若输成了姓名,和真正运行的时候域名不符,会出问题;

2.再次输入密码,第一次输入的是密钥库(keystore)的密码,第二次输入的是证书条目的密码

3.这里所说的证书库和密钥库是等同的(个人观点)

为了测试需要,这里再创建两个别名为test2和test3的证书条目在test.keystore密钥库中,代码如下:

Cmd代码  
  1. keytool -genkeypair -alias "test2" -keyalg "RSA" -keystore "test.keystore"  
  2. keytool -genkeypair -alias "test3" -keyalg "RSA" -keystore "test.keystore"  

 

2.查看证书库

Cmd代码  
  1. keytool -list -keystore test.keystore  

功能:

查看名为test.keystore的证书库中的证书条目

3.导出到证书文件

Cmd代码  
  1. keytool -export -alias test1 -file test.crt -keystore test.keystore  

功能:

将名为test.keystore的证书库中别名为test1的证书条目导出到证书文件test.crt中

4.导入证书的信息

Cmd代码  
  1. keytool -import -keystore test_cacerts -file test.crt   

 

功能:

将证书文件test.crt导入到名为test_cacerts的证书库中,

5.查看证书信息

Cmd代码  
  1. keytool -printcert -file "test.crt"   

 

功能:

查看证书文件test.crt的信息

6.删除密钥库中的条目

删除前查看密钥库test.keysote中的证书条目

Cmd代码  
  1. keytool -list -keystore test.keystore  

删除密钥库test.keystore中别名为test2的证书条目

Cmd代码  
  1. keytool -delete -keystore test.keystore -alias test2  

删除后查看密钥库test.keystore中的证书条目

Cmd代码  
  1. keytool -list -keystore test.keystore  

7.修改证书条目的口令

交互的方式

Cmd代码  
  1. keytool -keypasswd -alias test1 -keystore test.keystore  

 

功能:

将密钥库test.keystore中别名为test1的证书条目的密码修改为testtesttest1

非交互方式

Cmd代码  
  1. keytool -keypasswd -alias test1 -keypass testtesttest1 -new testtest1 -storepass testtest -keystore test.keystore  

功能:

将密钥库test.keystore中别名为test1的证书条目的密码修改为testtest1

 

我使用的命令:

keytool -genkey -alias friend -keypass friend4life -validity 10000 -keystore ijvmkeys
赋给ijvmkeys的密码是:ijvm2ed
keytool -genkey -alias stranger -keypass stranger4life -validity 10000 -keystore ijvmkeys

 

这里是将生成了两对私钥公钥和证书放在一个keystore里面,用别名区分。并且指定了keystore的展示密码为:ijvm2ed,条目的密码分别为:friend4life和stranger4life。

然后接下来使用jarsigner利用生成的秘钥证书进行签名:

jarsigner -keystore ijvmkeys -storepass ijvm2ed -keypass friend4life friend.jar friend
jar signer -keystore ijvmkeys -storepass ijvm2ed -keypass stranger4life stranger.jar stranger

 

然后使用jarsigner可以做签名校验:

将jar里的文件做修改,然后再次验证:

 

 

keystore文件不是证书,它可以使用命令得到证书。加密的私钥和公钥怎么得到呢?以及单独的证书怎么用Java方式得到呢?

之前一直在纠结这个问题,并且图为friend4life是我们的私钥,后面发现那只是仓库钥匙而已。私钥公钥等可以用Java代码得到:

 

package kunpu.security;

import sun.misc.BASE64Encoder;

import java.io.FileInputStream;
import java.io.FileWriter;
import java.security.*;
import java.security.cert.Certificate;

/**
 * @author zhen
 * @Date 2018/4/16 10:58
 */
public class ExportCert {

    //导出证书 base64格式
    public static void exportCert(KeyStore keyStore, String alias, String exportFile) throws Exception {
        Certificate certificate = keyStore.getCertificate(alias);
        BASE64Encoder encoder = new BASE64Encoder();
        String encoded = encoder.encode(certificate.getEncoded());
        FileWriter fw = new FileWriter(exportFile);
        fw.write("------Begin Certificate----- \\r\\n ");//非必须
        fw.write(encoded);
        fw.write("\\r\\n-----End Certificate-----");//非必须
        fw.close();
    }

    //得到KeyPair
    public static KeyPair getKeyPair(KeyStore keyStore, String alias, char[] password){
        try{
            Key key = keyStore.getKey(alias, password);
            if (key instanceof PrivateKey){
                Certificate certificate = keyStore.getCertificate(alias);
                PublicKey publicKey = certificate.getPublicKey();
                return new KeyPair(publicKey, (PrivateKey) key);
            }
        }catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e){
            e.printStackTrace();
        }
        return null;
    }

    //导出私钥
    public static void exportPrivateKey(PrivateKey privateKey, String exportFile) throws Exception {
        BASE64Encoder encoder = new BASE64Encoder();
        String encoded = encoder.encode(privateKey.getEncoded());
        FileWriter fileWriter = new FileWriter(exportFile);
        fileWriter.write("-----Begin Private Key-----\\r\\n");//非必须
        fileWriter.write(encoded);
        fileWriter.write("\\r\\n-----End Private Key-----");//非必须
        fileWriter.close();
    }

    //导出公钥
    public static void exportPublicKey(PublicKey publicKey, String exportFile) throws Exception {
        BASE64Encoder encoder = new BASE64Encoder();
        String encoded = encoder.encode(publicKey.getEncoded());
        FileWriter fileWriter = new FileWriter(exportFile);
        fileWriter.write("-----Begin Public Key-----\\r\\n");//非必须
        fileWriter.write(encoded);
        fileWriter.write("\\r\\n-----End Public Key-----");//非必须
        fileWriter.close();
    }

    public static void main(String[] args) throws Exception{
        String keyStoreType = "jks";
        String keystoreFile = "D:\\\\project\\\\workspace\\\\HelloWorld\\\\out\\\\production\\\\HelloWorld\\\\kunpu\\\\ijvmkeys";
        String password = "ijvm2ed"; //keystore的解析密码
        String friendPassword = "friend4life";//条目的解析密码

        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(new FileInputStream(keystoreFile), password.toCharArray());

        String alias = "friend";//条目别名
        String exportCertFile = "D:\\\\project\\\\workspace\\\\HelloWorld\\\\out\\\\production\\\\HelloWorld\\\\kunpu\\\\cert.txt";
        String exportPrivateFile = "D:\\\\project\\\\workspace\\\\HelloWorld\\\\out\\\\production\\\\HelloWorld\\\\kunpu\\\\privateKey.txt";
        String exportPublicFile = "D:\\\\project\\\\workspace\\\\HelloWorld\\\\out\\\\production\\\\HelloWorld\\\\kunpu\\\\publicKey.txt";

        ExportCert.exportCert(keyStore, alias, exportCertFile);
        KeyPair keyPair = ExportCert.getKeyPair(keyStore, alias, friendPassword.toCharArray()); //注意这里的密码是你的别名对应的密码,不指定的话就是你的keystore的解析密码
        ExportCert.exportPrivateKey(keyPair.getPrivate(), exportPrivateFile);
        ExportCert.exportPublicKey(keyPair.getPublic(), exportPublicFile);

        System.out.println("OK");

    }


}

 

代码当中遇到过问题,就是条目的密码指定错误了。没有指定默认使用的 是keystore的密码

 

 

 

jarsigner:jar的签名和校验工具

jarsigner - JAR 签名和校验工具

为 Java 归档 (JAR) 文件产生签名,并校验已签名的 JAR 文件的签名。

结构

jarsigner [ options ] jar-file alias
jarsigner -verify [ options ] jar-file

说明

jarsigner

为 Java 归档 (JAR) 文件签名 校验已签名的 JAR 文件的签名和完整性

JAR 功能使得类文件、图像、声音和其它数字化数据可打包到一个文件中,以便更方便快捷地发布。名为 jar 的工具使开发者可以生成 JAR 文件(从技术上来说,任何 zip 文件都可看作为 JAR 文件,尽管由 jar 创建或由 jarsigner 处理时,JAR 文件也包含一个 META-INF/MANIFEST.MF 文件)。

数字签名是一个根据某些数据(被“签名”的数据)和实体(人、公司等)的私钥计算出来的位字符串。与手写的签名一样,数字签名有很多有用的特性:

其真实性可被校验,方法是使用与生成签名的私钥对应的公钥进行计算。 它不可能被伪造(假设私钥没有泄露)。 它是已签名数据的函数,因此不能被声明为其它数据的签名。 已签名的数据不能被修改;如果被修改了,签名将不再被校验为可信的。

为了给文件生成一个实体的签名,该实体首先必须有一对与它相关的公/私钥对,以及一个或多个鉴别其公钥的证书。证书是由某个实体的数字化方式签发的声明,证明其它实体的公钥是某个特定的值。

jarsigner 使用来自密钥仓库的密钥和证书信息为 JAR 文件生成数字签名。密钥仓库是一个由私钥及其相关的 X.509 证书链(它鉴别相应公钥)组成的数据库。使用 keytool 实用程序来创建和管理密钥仓库。

jarsigner 使用实体的私钥创建签名。已签名的 JAR 文件包含(除了其它东西)一份来自密钥仓库的公钥(它对应于用于为该文件签名的私钥)的证书副本。jarsigner 可以使用已签名的 JAR 文件中的证书(在其签名块文件中)来校验其数字签名。

现在 jarsigner 只能为 JDK 的 jar 工具创建的 JAR 文件或 zip 文件签名(除了它们还有一个 META-INF/MANIFEST.MF 文件以外,JAR 文件与 zip 文件一样)。当 jarsigner 为 zip 文件签名时将自动创建这样的文件。

jarsigner 的缺省行为是签名 JAR(或 zip)文件。使用 -verify 选项将其替换为校验已签名的 JAR 文件。

JDK 1.1 的兼容性

keytool 和 jarsigner 工具完全替代了 JDK 1.1 中提供的 javakey 工具。这些新工具所提供的功能比 javakey 提供的多,包括能够用口令来保护密钥仓库和私钥,以及除了能够生成签名外还可以校验它们。

新的密钥仓库体系结构取代了 javakey 所创建和管理的身份数据库。密钥仓库格式和 1.1 版中 javakey 使用的数据库格式之间没有向后兼容。但是,

可以通过 keytool -identitydb 命令将身份数据库中的信息导入密钥仓库。 jarsigner 可以签名先前已用 javakey 签过名的 JAR 文件。 jarsigner 可以校验用 javakey 签名的 JAR 文件。因此,它识别并能处理来自 JDK 1.1 身份数据库而不是 JDK 1.2 密钥仓库的签名人别名。

下表解释了在 JDK 1.1.x 中签名的 JAR 文件在 JDK 1.2 中是如何处理的。

JAR 文件类型 在 1.1 数据库中的身份 从 1.1 数据库 (4) 导入到 1.2 密钥仓库的可信的身份 策略文件为 Identity/Alias
授特权 被授予的权利 已签名的 JAR 否 否 否 授予所有代码的缺省权利。 未签名的 JAR 否 否 否 授予所有代码的缺省权利。 已签名的 JAR 否 是 否 授予所有代码的缺省权利。 已签名的 JAR 是/不受信任 否 否 授予所有代码的缺省权利。(3) 已签名的 JAR 是/不受信任 否 是 授予所有代码的缺省权利。(1,3) 已签名的 JAR 否 是 是 授予所有代码的缺省权利加上策略文件中授予的权利。 已签名的 JAR 是/受信任 是 是 授予所有代码的缺省权利加上策略文件中授予的权利。(2) 已签名的 JAR 是/受信任 否 否 所有权利 已签名的 JAR 是/受信任 是 否 所有权利 (1) 已签名的 JAR 是/受信任 否 是 所有权利 (1)

注意:

如果策略文件中提到了 identity/alias,则它必须导入到密钥仓库中,以使策略文件影响授予的权利。 策略文件/密钥仓库组合在身份数据库中优先于可信任的身份。 JDK 1.2 中忽略不可信任的身份。 只有可信任的身份才能导入到 JDK 1.2 密钥仓库。

密钥仓库别名

所有密钥仓库实体都须通过唯一的别名来访问。

当使用 jarsigner 签名 JAR 文件时,必须为包含用于生成签名的私钥的密钥仓库实体指定别名。例如,下面命令将使用与别名“duke”(它在“working”目录下的名为“mystore”的密钥仓库中)相关联的私钥为名为“MyJARFile.jar”的 JAR 文件签名。因为没有指定输出文件,它将用已签名的 JAR 文件覆盖 MyJARFile.jar。

    jarsigner -keystore /working/mystore -storepass myspass
      -keypass dukekeypasswd MyJARFile.jar duke

密钥仓库被口令保护,因此必须指定仓库口令(此处为“myspass”)。如果在命令行中没有指定它,将提示需要它。同样,私钥也被口令保护在密钥仓库中,因此必须指定该私钥的口令(此处为“dukekeypasswd”),如果没有在命令行中指定它或与仓库口令不一样,将提示需要它。

密钥仓库位置

jarsigner

有一个 -keystore 选项用于指定要使用的密钥仓库的 URL。按默认,密钥仓库储存在用户宿主目录(由系统属性的 "user.home" 决定)中名为 .keystore 的文件中。在 Solaris 系统中 "user.home" 默认为用户的宿主目录。

密钥仓库实现

java.security

目前有两个命令行工具(keytool 和 jarsigner),以及一个基于 GUI 的工具(名为 Policy Tool)利用密钥仓库实现。由于密钥仓库是公用的, JDK 用户可编写其它的使用该密钥仓库的安全性应用程序。

有个固有的默认实现,是由 Sun Microsystems 公司提供的。它利用名为“JKS” 的专用密钥仓库类型(格式),将密钥仓库实现为一个文件。它用单个口令保护每个私钥,也用口令(可能为另一个口令)保护整个密钥仓库的完整性。

密钥仓库的实现基于提供者。具体地说,由 keystore 所提供的应用程序接口是借助于“服务提供者接口”(SPI) 来实现的。也就是说,有对应的抽象 KeystoreSpi 类,也是在 java.security 包中,它定义了“提供者”必须实现的服务提供者接口方法(“提供者”指的是一个或一组包,这个或这组包提供了一部份可由 JDK 安全 API 访问的那些服务的具体实现)。因此,要提供密钥仓库实现,客户必须实现提供者并提供 KeystoreSpi 子类实现,如如何为 Java 加密体系结构实现 提供者 中所述。

通过使用 KeyStore 类中提供的“getInstance”工厂方法,应用程序可从不同的提供者中挑选不同类型的密钥仓库实现。密钥仓库类型定义密钥仓库信息的存储和数据格式,以及用于保护密钥仓库中的私钥和密钥仓库自身完整性的算法。不同类型的密钥仓库实现是不兼容的。

keytool 可以使用任何基于文件的密钥仓库实现 (它把在命令行中传递给它的密钥仓库位置当成文件处理并将之转换为文件输入流,从该文件输入流中加载密钥仓库信息)。另一方面,jarsigner 和 policytool 工具可从任何可用 URL 指定的位置读取某个密钥仓库。

对于 jarsigner 和 keytool,可以通过 -storetype 选项在命令行中指定密钥仓库类型。对于 策略工具,可通过“编辑”菜单中的“更改密钥仓库”命令来指定密钥仓库类型。

如果没有显式地指定密钥仓库类型,这些工具将只是根据安全属性文件中指定的 keystore.type 属性值来选择密钥仓库实现。安全属性文件名叫 java.security,它位于 JDK 安全属性目录 java.home/lib/security 中,其中 java.home 为 JDK 的安装目录。

每个工具都先获取 keystore.type 的值,然后检查所有当前已安装的提供者直到找到实现所要求类型的密钥仓库的提供者为止。然后就使用该提供者的密钥仓库实现。

KeyStore 类定义了名为 getDefaultType 的静态方法,它可让应用程序或 applet 检索 keystore.type 属性的值。以下代码将创建默认密钥仓库类型(此类型由 keystore.type 属性所指定)的实例:

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

默认的密钥仓库类型是 "jks" (这是由 "SUN" 提供的密钥仓库实现的专用类型)。它在安全性属性文件中由下面这行进行指定:

    keystore.type=jks

要使工具利用非缺省的密钥仓库实现,请更改此行以指定不同的密钥仓库类型。

如果您有这样的提供者包,它给出名为 "pkcs12" 的密钥仓库类型的密钥仓库实现,则可将前面提到的那行改为:

    keystore.type=pkcs12

注意: 密钥仓库类型的命名中大小写无关紧要。例如,"JKS" 将被认为是与 "jks" 相同的。

包中提供的 KeyStore 类为访问和修改密钥仓库中的信息提供了相当固定的接口。可以有多个不同的具体实现,其中每个实现都是对某个特定类型的密钥仓库的具体实现。

支持的算法

现在 jarsigner 使用二者都可以签名 JAR 文件。

带 SHA-1 报文摘要算法的DSA (数字签名算法),或 带 MD5 报文摘要算法的 RSA 算法。

也就是说,如果签名人的公钥和私钥是 DSA 密钥,则 jarsigner 将使用“SHA1withDSA”算法为 JAR 文件签名。如果签名人的密钥是 RSA 密钥,jarsigner 将试图使用“MD5withRSA”算法为 JAR 文件签名。这只有静态地安装了提供“MD5withRSA”算法实现的提供者才可能(来自缺省的“SUN”提供者的“SHA1withDSA”算法总是可用的)。

已签名的 JAR 文件

当 jarsigner 被用于为 JAR 文件签名时,输出的已签名 JAR 文件与输入 JAR 文件完全一样,除了它在 META-INF 目录下有两个附加文件:

扩展名为 .SF 的签名文件,以及 扩展名为 .DSA 的签名块文件。

这两个文件的基本文件名来自 -sigFile 选项。例如,如果该选项为

  -sigFile MKSIGN

则这两个文件分别为“MKSIGN.SF”和“MKSIGN.DSA”。

如果命令行中没有 -sigfile 选项,则 .SF 和 .DSA 文件的基本文件名将是命令行中指定的别名的前 8 个字符,并全部被转换为大写。如果别名少于 8 个字符,将使用整个别名。如果别名中包含签名文件名所不允许的字符,则形成文件名时这样的字符将被转换为下划线 ("_")。合法的字符包括字母、数字、下划线和连字符。

签名 (.SF) 文件

签名文件(.SF 文件)与清单文件相似,后者总是在用 jarsigner 对文件进行签名时包含在 JAR 文件中。也就是说,对于 JAR 文件中包含的每个源文件,.SF 文件与清单文件一样有如下三行:

文件名, 使用的报文摘要算法 (SHA),以及 SHA 摘要值。

在清单文件中,SHA 每个源文件的摘要值是源文件中二进制数据的摘要 (散列)。而在 .SF 文件中,给定源文件的摘要值是该源文件的清单文件中的三行的散列。

缺省情况下签名文件还包含一个含有整个清单文件的散列的头。这个头使得可以进行校验优化,如 JAR 文件校验所述。

签名块 (.DSA) 文件

.SF 文件被签名且签名被放入 .DSA 文件。.DSA 文件还包含来自密钥仓库的证书或证书链(被编码到其中),它们鉴别与用于签名的私钥对应的公钥。

JAR 文件校验

如果签名合法,并且签名生成时在 JAR 文件中的文件从此没有更改过,JAR 文件校验将成功。JAR 文件校验包括下列步骤:

校验 .SF 文件本身的签名。

也就是说,校验确保保存在每个签名块 (.DSA) 文件中的签名的确是使用与公钥(其证书或证书链也出现在该 .DSA 文件中)对应的私钥生成的。它还确保该签名是相应签名 (.SF) 文件的合法签名,因此 .SF 文件没有被更改过。

将列在 .SF 文件的每个项中的摘要与清单中相应的部分进行校验。

.SF 文件缺省地包含一个含有整个清单文件的散列的头。该头存在时,校验将检查头中的散列是否匹配清单文件的散列。如果匹配,校验将进行下一步。

如果不匹配,则需一个次优的校验以确保 .SF 文件中的每个源文件信息部分的散列等于清单文件中的相应部分的散列(参见签名 (.SF) 文件)。

保存在 .SF 文件头中的清单文件的散列不等于当前清单文件的散列的一种原因可能是因为生成签名(因此生成 .SF 文件)后一个或多个文件被添加到 JAR 文件中(使用 jar 工具)。当 jar 工具用于添加文件时,清单文件被更改(为新文件添加了节),但 .SF 文件没有更改。如果签名生成时在 JAR 文件中的文件从此没有更改过,校验仍被认为是成功的,这种情况下 .SF 文件的非头部分中的散列与清单文件中相应部分的散列相等。

读取 JAR 中每个在 .SF 文件中有相应项的文件。读取时,计算文件的摘要,然后将结果与清单中该文件的摘要部分进行比较。摘要应相同,否则校验将失败。

如果在校验期间发生了严重的校验错误,则该进程终止并抛出安全异常。它将被 jarsigner捕获并显示。

一个 JAR 文件多个签名

JAR 文件可以被多个人使用 jarsigner 工具进行多次签名,每次为不同的人指定别名,如下:

  jarsigner myBundle.jar susan
  jarsigner myBundle.jar kevin

JAR 文件被多次签名时,产生的 JAR 文件中将有多个 .SF 和 .DSA 文件,每个签名有一对。因此,在上例中,输出的 JAR 文件将包含下列文件:

  SUSAN.SF
  SUSAN.DSA
  KEVIN.SF
  KEVIN.DSA

注意: JAR 文件可以有混合签名,有些是 JDK 1.1 javakey 工具生成的,其它是 jarsigner 生成的。也就是说,jarsigner 可用于为先前已使用 javakey 签过名的 JAR 文件签名。

工具用于两个目的:

选项

下面列出并说明了各种 jarsigner 选项。注意:

  • 所有选项名前都有一个减号 (-)。
  • 选项可以以任何次序提供。
  • 斜体项(选项值)代表必须提供的实际值。
  • -keystore-storepass-keypass-sigfile 和 -signedjar 选项仅在为 JAR 文件签名时相关,而不是在校验已签名的 JAR 文件时。同样,别名仅在为 JAR 文件签名时在命令行中指定。
-keystore url
指定密钥仓库的 URL。缺省值是用户的宿主目录中的 .keystore 文件,它由系统属性“user.home”决定。

签名时需要密钥仓库,因此如果没有缺省的(或要使用非缺省的)密钥仓库,就必须明确指定一个。

校验时需要密钥仓库,但如果指定了一个,或存在缺省的,且 -verbose 选项也被指定了,则将输出该密钥仓库中是否包含了用于校验 JAR 文件的证书的附加信息。

注意: -keystore 参数实际上可以是指定的文件名(及路径)而不是 URL,这种情况下它将当作“file:” URL. 也就是说,

  -keystore filePathAndName

被当作等价于

  -keystore file:filePathAndName
-storetype storetype
指定要被实例化的密钥仓库类型。默认的密钥仓库类型是安全属性文件中 "keystore.type" 属性值所指定的那个类型,由 java.security.KeyStore 中的静态方法 getDefaultType 返回。
-storepass password
指定访问密钥仓库所需的口令。这仅在签名(不是校验)JAR 文件时需要。在这种情况下,如果命令行中没有提供 -storepass 选项,用户将被提示输入口令。

注意: 口令不应在命令行或脚本中指定,除非是为了测试,或在安全系统中。并且,在口令提示下键入口令时将显示出键入的字符,因此不要在其它人面前键入。

-keypass password
指定用于保护密钥仓库项(由命令行中指定的别名标出)的私钥的口令。使用 jarsigner 为 JAR 文件签名时需要该口令。如果命令行中没有提供口令,且所需的口令与密钥仓库的口令不同,则将提示用户输入它。

注意: 口令不应在命令行或脚本中指定,除非是为了测试,或在安全系统中。并且,在口令提示下键入口令时将显示出键入的字符,因此不要在其它人面前键入。

-sigfile file
指定用于生成 .SF 和 .DSA 文件的基本文件名。例如,如果 file 为“DUKESIGN”,则生成的 .SF 和 .DSA 文件将被命名为“DUKESIGN.SF”和“DUKESIGN.DSA”,并将放到已签名的 JAR 文件的“META-INF”目录中。

file 中的字符应来自“a-zA-Z0-9_-”。也就是说,只允许字母、数字、下划线和连字符。注意: .SF 和 .DSA 文件名中小写字母将被转换为大写字母。

如果命令行中没有 -sigfile 选项,则 .SF 和 .DSA 文件的基本文件名将是命令行中指定的别名的前 8 个字符,并全部被转换为大写。如果别名少于 8 个字符,将使用整个别名。如果别名中包含签名文件名所不允许的字符,则形成文件名时这样的字符将被转换为下划线 ("_")。

-signedjar file
指定用于已签名的 JAR 文件的名称。

如果命令行中没有指定名称,将使用输入的 JAR 文件名(要签名的 JAR 文件名);换句话说,该文件将被签名 JAR 文件覆盖。

-verify
如果它出现在命令行中,则指定的 JAR 文件将被校验,而不是签名。如果校验成功,将显示“jar verified”。如果试图校验未签名的 JAR 文件,或校验被不支持的算法(例如未安装 RSA 提供者时使用的 RSA)签名的 JAR 文件,则将有如下显示: "jar is unsigned. (signatures missing or not parsable)"

可以校验使用 jarsigner 或 JDK 1.1 javakey 工具或共用二者签名的 JAR 文件。

有关校验的详细信息,参见 JAR 文件校验

-certs
如果它与 -verify 和 -verbose 选项一起出现在命令行中,则输出将包括 JAR 文件的每个签名人的证书信息。该信息包括
  • 验证签名人公钥的证书的类型名(保存在 .DSA 文件中)
  • 如果该证书是 X.509 证书(更准确地说是 java.security.cert.X509Certificate 的实例): 签名人的特征名

密钥仓库也被检查。如果命令行中没有指定密钥仓库值,缺省密钥仓库文件(如果有)将被检查。如果签名人的公钥证书与密钥仓库中的项匹配,则还将显示下列信息:

  • 该签名人的密钥仓库项的别名,在圆括号中。如果该签名人实际上来自于 JDK 1.1 身份数据库而不是密钥仓库,则别名将显示在方括号而不是圆括号中。
-verbose
如果它出现在命令行中,则代表“verbose”模式,它使 jarsigner 在 JAR 签名或校验过程中输出额外信息。
-internalsf
过去,JAR 文件被签名时产生的 .DSA(签名块)文件包含一个同时产生的 .SF 文件(签名文件)的完整编码副本。这种做法已被更改。为了减小输出 JAR 文件的整个大小,缺省情况下 .DSA 文件不再包含 .SF 文件的副本。但是如果 -internalsf 出现在命令行中,将采用旧的做法。该选项主要在测试时有用;实际上不应使用它,因为这样将消除有用的优化。
-sectionsonly
如果它出现在命令行中,则 JAR 文件被签名时生成的 .SF 文件(签名文件)将包括含有整个清单文件的散列的头。它仅包含 与 JAR 中每个单独的源文件相关的信息和散列,如签名 (.SF) 文件所述。

缺省情况下,该头将作为一种优化手段添加。只要该头存在,则无论何时 JAR 被校验,都将首先检查该头中的散列是否真正与整个清单文件的散列匹配。如果匹配,校验将进行下一步。如果不匹配,则有必要执行一个次优的校验,检查 .SF 文件中每个源文件信息部分中的散列是否等于清单文件中相应部分的散列。

有关的详细信息,参见 JAR 文件校验

该选项主要在测试时有用;实际上不应使用它,因为这样将消除有用的优化。

-Jjavaoption
将指定的 javaoption 串直接传递到 Java 解释器。((jarsigner 实际上是解释器的一个 “wrapper”)。该选项不应含有任何空格。它有助于调整执行环境或内存使用。要获得可用的解释器选项的清单,可在命令行键入 java -h 或 java -X

程序例子

签名 JAR 文件

假设您有一个 JAR 文件名为“bundle.jar”并且希望使用“working”目录中名为“mystore”的密钥仓库里别名为“Jane”的用户的私钥进行签名。假设密钥仓库口令是“myspass”且 jane 的私钥口令是“j638klm”。您可以使用下列命令为该 JAR 文件签名并将签了名的 JAR 文件命名为“sbundle.jar”:

    jarsigner -keystore /working/mystore -storepass myspass
      -keypass j638klm -signedjar sbundle.jar bundle.jar jane

注意上面的命令中没有指定 -sigfile,因此所产生的要放入已签名 JAR 文件的 .SF 和 .DSA 文件将采用基于别名的缺省名。也就是说,它们将被命名为 JANE.SF 和 JANE.DSA

如果要根据提示输入仓库口令和私钥口令,可以将上面的命令缩短为

    jarsigner -keystore /working/mystore
      -signedjar sbundle.jar bundle.jar jane

如果要使用的是缺省密钥仓库(它在宿主目录中,名为“.keystore”),则不必指定密钥仓库,如下:

    jarsigner -signedjar sbundle.jar bundle.jar jane

最后,如果要使已签名的 JAR 文件简单地覆盖输入的 JAR 文件 (bundle.jar),则不必指定 -signedjar 选项:

    jarsigner bundle.jar jane

校验已签名的 JAR 文件

要校验已签名的 JAR 文件,(也就是说验证签名合法且 JAR 文件未被更改过)请使用如下命令:

    jarsigner -verify sbundle.jar

如果校验成功,将显示

    jar verified.

。否则将出现错误信息。

如果使用 -verbose 选项则将获得更多的信息。下面是用 -verbose 选项使用 jarsigner 的例子及其输出:

    jarsigner -verify -verbose sbundle.jar

           198 Fri Sep 26 16:14:06 PDT 1997 META-INF/MANIFEST.MF
           199 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.SF
          1013 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.DSA
    smk   2752 Fri Sep 26 16:12:30 PDT 1997 AclEx.class
    smk    849 Fri Sep 26 16:12:46 PDT 1997 test.class

      s = signature was verified
      m = entry is listed in manifest
      k = at least one certificate was found in keystore

    jar verified.

校验证书信息

如果校验时与 -verify 和 -verbose 选项一起指定了 -certs 选项,则输出将包括该 JAR 文件的每个签名人的证书信息,其中包括证书类型、签名人的特征名信息(如果是 X.509 证书),以及括在圆括号中的签名人的密钥仓库别名(如果 JAR 文件中的公钥证书与密钥仓库项中的证书匹配。例如:

    jarsigner -keystore /working/mystore -verify -verbose -certs myTest.jar

           198 Fri Sep 26 16:14:06 PDT 1997 META-INF/MANIFEST.MF
           199 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.SF
          1013 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.DSA
           208 Fri Sep 26 16:23:30 PDT 1997 META-INF/JAVATEST.SF
          1087 Fri Sep 26 16:23:30 PDT 1997 META-INF/JAVATEST.DSA
    smk   2752 Fri Sep 26 16:12:30 PDT 1997 Tst.class

      X.509, CN=Test Group, OU=Java Software, O=Sun Microsystems, L=CUP, S=CA, C=US (javatest)
      X.509, CN=Jane Smith, OU=Java Software, O=Sun, L=cup, S=ca, C=us (jane)

      s = signature was verified
      m = entry is listed in manifest
      k = at least one certificate was found in keystore

    jar verified.

如果签名人的证书不是 X.509 证书,将没有特征名信息。这种情况下,仅显示证书类型和别名。例如,如果该证书为 PGP 证书,且别名为“bob”,则将显示

      PGP, (bob)

校验包含身份数据库签名人的 JAR 文件

如果 JAR 文件已用 JDK 1.1 javakey 工具签名,因此签名人是身份数据库中的别名,则校验输出将包括一个“i”符号。如果 JAR 文件同时被身份数据库中的别名和密钥仓库中的别名二者签名,则将出现“k”和“i”。

当使用了 -certs 选项时,任何身份数据库别名都将显示在方括号中,而不是显示在用于密钥仓库别名的圆括号中。例如:

    jarsigner -keystore /working/mystore -verify -verbose -certs writeFile.jar

           198 Fri Sep 26 16:14:06 PDT 1997 META-INF/MANIFEST.MF
           199 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.SF
          1013 Fri Sep 26 16:22:10 PDT 1997 META-INF/JANE.DSA
           199 Fri Sep 27 12:22:30 PDT 1997 META-INF/DUKE.SF
          1013 Fri Sep 27 12:22:30 PDT 1997 META-INF/DUKE.DSA
   smki   2752 Fri Sep 26 16:12:30 PDT 1997 writeFile.html

      X.509, CN=Jane Smith, OU=Java Software, O=Sun, L=cup, S=ca, C=us (jane)
      X.509, CN=Duke, OU=Java Software, O=Sun, L=cup, S=ca, C=us [duke]

      s = signature was verified
      m = entry is listed in manifest
      k = at least one certificate was found in keystore
      i = at least one certificate was found in identity scope

    jar verified.

注意别名“duke”在方括号中,这说明它是身份数据库别名,不是密钥仓库别名。

以上是关于使用keytool生成公钥私钥证书并且读取出来,使用私钥签名jar并验证(转)的主要内容,如果未能解决你的问题,请参考以下文章

如何利用keytool工具生成数字证书

keytool生成证书与tomcat 的SSL的配置使用

Java Keytools 证书转换成Openssl 的PEM 文件或keytools 导出私钥文件

从jks证书中提取公钥和私钥(jks证书转pem证书)

Springboot整合TrueLicense(包括License的生成安装和验证)

如何使用OpenSSL工具生成根证书与应用证书