JAR文件可以用 jarsigner工具或者直接通过 java.securityAPI 签名。签名后的JAR 本身的文件文件与原来JAR本身的 文件完全相同,只是更新了它的 manifest文件,并在 META-INF 目录中增加了两个文件,一个签名文件和一个签名块文件。


如果你对数字签名还不熟悉,请先阅读《数字签名简介》,《Java的数字签名和数字证书



JAR文件可以用一个存储在 Keystore数据库中的证书进行签名的。存储在 keystore 中的证书有密码保护,必须向 jarsigner工具提供这个密码才能对 JAR 文件签名。


图 1. Keystore 数据库




  Jar文件使用jarsigner签名以后,在META-INF文件夹下会多出两个文件:

XXX.SF文件 与 XXX.YYY 文件。XXX应该与你签名时使用密钥的别名一致.而XXX.YYY的扩展名,根据数字签名的类型RSA、DSA 或者 PGP 以及用于签名 JAR 的证书类型而有不同的扩展名。XXX.SF文件的格式类似于 manifest 文件(一组 RFC-822 头)。 XXX.SF 文件主要包括的对JAR本身文件及Manifest文件的签名码(加密后的散列码)。奇怪的是进行签名后Manifest文件中也有针对JAR本身文件的签名码,且和 XXX.SF 文件中的不一样。为什么会有两个呢?不解。在 XXX.YYY 文件(比如TEST.RSA)中,除了签名私钥所对应的公钥外,还包含了签名者的一些信息。

在验证一个签名的 JAR 时,将签名文件的摘要值与对 JAR 文件中的相应项计算的摘要值进行比较。


MANIFEST.MF文件:


Manifest-Version: 1.0
  
Created-By: 1.6.0_11 (Sun Microsystems Inc.)
  
Main-Class: Hello
  

  
Name: Util.class
  
SHA1-Digest   : UQkSPocH+hEH4W8d4/E7ifo7Y2A=
  

  
Name: Hello.class
  
SHA1-Digest   : HQJfMvXm5JhrX2afxITiicvzDdQ=


TEST.SF文件


Signature-Version: 1.0
  
SHA1-Digest-Manifest-Main-Attributes: +yrcddwVI7QFdviahKRNKIHg2Zc=
  
Created-By: 1.6.0_11 (Sun Microsystems Inc.)
  
SHA1-Digest-Manifest: dCxOoUzPsGXrxxYH5PRNx47Er7M=
  

  
Name: Util.class
  
SHA1-Digest: 5g4n0t4ScMDowIF10vD7pMtcM1g=
  

  
Name: Hello.class
  
SHA1-Digest: OvGpI1SCZ7Py8O0rjqUUsZT6H/Q=


Keystore


要签名一个 JAR 文件,必须首先有一个私钥。私钥及其相关的公钥证书存储在名为keystores的、有密码保护的数据库中。JDK 包含创建和修改 keystores 的工具。keystore 中的每一个密钥都可以用一个别名标识,它通常是拥有这个密钥的签名者的名字。


所有 keystore 项 ( 密钥和信任的证书项 ) 都是用唯一别名访问的。别名是在用 keytool -genkey 命令生成密钥对 ( 公钥和私钥 ) 并在 keystore 中添加项时指定的。之后的 keytool命令必须使用同样的别名引用这一项。


例如,要生成一个别名为“robin”生成一个新的公钥 / 私钥对并将公钥包装到自签名的证书中,要使用下述命令:


例1


keytool -genkey  -alias   robin   -keystore   robin.keystore  -storepass  GL2009  -keypass  gl2009  -validity  100  -keyalg  RSA  -keysize  1024  -sigalg  MD5withRSA


这个命令序列用于生成一个名为的 公钥/私钥对 名字为 robin ,并把它添加到文件名为 robin.keystore 的keystore文件中,如果该文件还不存在,则创建它。其中文件名密码为 GL2009 ,要添加的 公钥/私钥对的 私钥密码为 gl2009 ,文件有效期为 100 天, 公钥/私钥对 名字为 robin, 公钥/私钥对采用 RSA 算法, 公钥/私钥的长度为 1024 , 签名时采用 MD5withRSA 算法(用 MD5 算法进行散列,用 RSA 算法对其散列码进行加密)


然后按照提示输入一些信息,如下:


What is your first and last name?
    
  [Unknown]:       hubing
    
What is the name of your organizational unit?
    
  [Unknown]:       GL
    
What is the name of your organization?
    
  [Unknown]:       gameloft
    
What is the name of your City or Locality?
    
  [Unknown]:       chengdu
    
What is the name of your State or Province?
    
  [Unknown]:       shichuan
    
What is the two-letter country code for this unit?
    
  [Unknown]:       cn
    
Is CN=hubing, OU=GL, O=gameloft, L=chengdu, ST=shichuan, C=cn correct?
    
  [no]:       yes


jarsigner 工具


通过jarsigner工具,可以使用 keystore 生成或者验证 JAR 文件的数字签名。


假设像 例1 那样创建了keystore文件 robin.keystore ,可以用下面的命令签名一个 JAR 文件:


例2


jarsigner  -keystore   robin.keystore   -storepass   GL2009  -keypass   gl2009  Hello.jar  robin


这个命令用密码“ GL2009 ”从名为“ robin.keystore ”的keystore文件中提出名字为“ robin ”、密码为“ gl2009 ”的 公钥/私钥对 ,并对Hello.jar 文件按照 keystore文件 robin.keystore 中的约定进行数字签名。


例3


jarsigner  -keystore   robin.keystore  -storepass  GL2009  -keypass  gl2009  -signedjar   Hello_signed.jar  Hello.jar robin


这个命令用密码“GL2009”从名为“robin.keystore”的keystore文件中提出名字为“robin”、密码为“gl2009”的公钥/私钥对,并对Hello.jar 文件按照keystore文件robin.keystore中的约定进行数字签名,签名的输出文件为 Hello_signed.jar 。


jarsigner工具还可以验证一个签名的 JAR 文件,很简单,只需执行以下命令:


 jarsigner -verify Hello.jar 


如果签名的 JAR 文件没有被篡改过,那么 jarsigner工具就会告诉您 JAR 通过验证了。否则,它会抛出一个 SecurityException, 表明哪些文件没有通过验证。 还可以用 java.util.jar和 java.securityAPI 以编程方式签名 JAR