Jar 包
添加时间:2013-7-17 点击量:
1,加密、择要和数字
(1)公钥加密算法
关于公钥加密算法,参考维基百科词条 Public-key cryptography。
公钥加密算法又称为非对称密钥加密算法,因为它包含一个公钥-私钥对,称为key pair。即 key pair = private key + public key。
从功能上说,两个key感化雷同,用一个key加密的消息,只能用另一个key解密,反之亦然。两个 key 的差别只在于谁拥有/知道它:private key 只有 key pair 的生成者知道,public key 则公开。key pair 的另一个特点是无法从一个 key 推算出另一个 key。
常用公钥加密算法是RSA和DSA。(TODO: 差别?)
(2)数字
关于数字,参考维基百科词条 Digital signature。
数字算法是基于公钥加密算法的,其过程是:
- 生成 key pair
- :对消息进行择要获得其Hash值;用 private key 加密消息Hash获得数字(Signature)
- 验证:对消息进行择要获得其Hash值;用 public key 解开数字获得消息Hash;对两个Hash进行比对
因为 private key 无法捏造或从 public key 推算出,是以,消息发送者必为 private key 拥有者,由此确保了消息起原的真实性(Authentication)和不成否定性(Non-repudiation)。若是消息在发送过程中破坏或被批改,进行择要后Hash值必然不一致,数字验证无法经由过程,由此确保了消息内容的完全性(Integrity)。
(3)消息择要
关于消息择要,参考维基百科词条 Cryptographic hash function。
消息择要算法是应用一个Hash函数对随便率性长度的输入数据进行处理惩罚,输出固定长度的数据。输出数据称为消息择要。无法从消息择要倒推出消息内容。常用的消息择要算法是 MD5 和 SHA-1。(TODO: 差别?)
2,Jar 包和验证
对Jar包的数字和验证过程和前面描述的数字道理和过程一致。Jar包是待发送的消息,经过后,Jar包内置入了数字和public key,验证者可以应用这两项数据进行验证。
实际上,经的Jar包内包含了以下内容:
- 原Jar包内的class文件和资料文件
- 文件 META-INF/.SF:这是一个文本文件,包含原Jar包内的class文件和资料文件的Hash
- block文件 META-INF/.DSA:这是一个数据文件,包含者的 certificate 和数字。此中 certificate 包含了者的有关信息和 public key;数字是对 .SF 文件内的 Hash 值应用 private key 加密得来
(1)应用 keytool 和 jarsigner 对象进行 Jar 包和验证
JDK 供给了 keytool 和 jarsigner 两个对象用来进行 Jar 包和验证。
keytool 用来生成和经管 keystore。keystore 是一个数据文件,存储了 key pair 有关的2种数据:private key 和 certificate,而 certificate 包含了 public key。全部 keystore 用一个暗码进行保护,keystore 里面的每一对 key pair 零丁用一个暗码进行保护。每对 key pair 用一个 alias 进行指定,alias 不区分大小写。
keytool 支撑的算法是:
- 若是公钥算法为 DSA,则择要算法应用 SHA-1。这是默认的
- 若是公钥算法为 RSA,则择要算法采取 MD5
jarsigner 读取 keystore,为 Jar 包进行数字。jarsigner 也可以对的 Jar 包进行验证。
下面以 JDK 中的 tools.jar 包为例,应用 keytool 和 jarsigner 对它进行和验证。
第1步:用 keytool 生成 keystore
履行以下号令,生成文件名为 test.ks 的 keystore,并生成 alias 为 testkey 的 key pair
keytool -keystore test.ks -genkey -alias testkey
按照屏幕提示输入各项信息
输入keystore暗码:
再次输入新暗码:
您的名字与姓氏是什么?
[Unknown]:
您的组织单位名称是什么?
[Unknown]:
您的组织名称是什么?
[Unknown]:
您地点的城市或区域名称是什么?
[Unknown]:
您地点的州或省份名称是什么?
[Unknown]:
该单位的两字母国度代码是什么
[Unknown]:
CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown 正确吗?
[否]: y
输入<testkey>的主暗码
(若是和 keystore 暗码雷同,按回车):
再次输入新暗码:
第2步:用 jarsigner 对 Jar 包进行
履行号令并按提示输入 keystore 和 testkey 的暗码后,即可对 tools.jar 进行并输出为 tools_signed.jar
jarsigner -keystore test.ks -signedjar tools_signed.jar tools.jar testkey
输入密钥库的口令短语:
输入 testkey 的密钥口令:
警告:
者将在六个月内过期。
第3步:用 jarsigner 对 Jar 包进行验证
履行以下号令,验证Jar 包是否有效
jarsigner -verify tools_signed.jar
输出
jar 已验证。
警告:
此 jar 包含者将在六个月内过期的条目。
要懂得具体信息,请应用 -verbose 和 -certs 选项从头运行。
重视,以上号令只是应用 Jar 包内的文件,验证 public key 与生成的 private key 是否是有效 key pair,以及 Jar 包内容是否完全,并没有和 keystore 进行比对。若是须要验证 Jar 包是否是应用某一 keystore 内的密钥进行的,可以指定如下的号令和选项:
jarsigner -verify -verbose -keystore test.ks tools_signed.j
ar
输出如下,重视对每一个class或资料文件,前面状况标识表记标帜中包含k,注解在 keystore 中找到了匹配的 certificate,也就是找到了匹配的 public key。若是须要打印出每一个 class文件或资料文件的 certificate 具体信息,可以增长 -certs 选项
...
smk 3384 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/HotSpotAttachProvider.class
smk 4597 Tue Jul 19 01:52:50 CST 2011 sun/tools/attach/HotSpotVirtualMachine.class
smk 3487 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsAttachProvider.class
smk 1001 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsVirtualMachine¥PipedInputStream.class
smk 2796 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsVirtualMachine.class
0 Tue Jul 19 01:52:50 CST 2011 sun/tools/jstack/
smk 4113 Tue Jul 19 01:52:50 CST 2011 sun/tools/jstack/JStack.class
0 Tue Jul 19 01:53:02 CST 2011 sun/tools/jinfo/
smk 4325 Tue Jul 19 01:53:02 CST 2011 sun/tools/jinfo/JInfo.class
0 Tue Jul 19 01:52:56 CST 2011 sun/tools/jmap/
smk 8177 Tue Jul 19 01:52:56 CST 2011 sun/tools/jmap/JMap.class
s = 已验证
m = 在清单中列出条目
k = 在密钥库中至少找到了一个
i = 在身份感化域内至少找到了一个
jar 已验证。
警告:
此 jar 包含者将在六个月内过期的条目。
要懂得具体信息,请应用 -verbose 和 -certs 选项从头运行。
(2)编程进行 Jar 包的验证
可以应用以下API在运行时对 Jar 包进行验证:
- java.util.jar.JarFile
- java.util.jar.JarEntry
- java.security.KeyStore
- java.security.cert.Certificate
读取 keystore 内的 certificate:
final String ksPath = ...
final String ksPass = ...
final HashMap<String, Certificate> certMap = new HashMap<String, Certificate>();
InputStream in = new FileInputStream(ksPath);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, ksPass.toCharArray());
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate cert = s.getCertificate(alias);
certMap.put(alias, cert);
}// while
验证 Jar 包:
final String jarPath = G:\\tmp\\jar_sign_test\\tools_signed.jar;
JarFile jar = new JarFile(jarPath, true);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
// Verify the entry
InputStream in = jar.getInputStream(entry);
try {
drain(in);
} finally {
try {
in.close();
} catch (Exception e) {
}
}
Certificate[] certs = entry.getCertificates();
if (null != certs && certs.length > 0) {
for (Certificate cert : certs) {
String alias = verify(cert, certMap);
if (null == alias) {
...
} else {
...
}
}// for
}
} // while
按照 JarEntry.getCertificates() 办法 Java doc,在调用之前,必须起首将此 JarEntry 数据完全读取,是以上方的代码段中调用了一个 drain() 办法:
private static void drain(InputStream in) throws IOException {
byte[] buf = new byte[512];
while (-1 != in.read(buf))
;
}
verify() 办法用来搜检 certificate 是否与 keystore 内的某个 certificate 匹配,首要用到了 Certificate.verify(PublicKey ) 办法:
private static String verify(Certificate cert, HashMap<String, Certificate> map) {
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String alias = it.next();
try {
cert.verify(map.get(alias).getPublicKey());
return alias;
} catch (Exception e) {
continue;
}
}// while
return null;
}
我们永远不要期待别人的拯救,只有自己才能升华自己。自己已准备好了多少容量,方能吸引对等的人与我们相遇,否则再美好的人出现、再动人的事情降临身边,我们也没有能量去理解与珍惜,终将擦肩而过。—— 姚谦《品味》
1,加密、择要和数字
(1)公钥加密算法
关于公钥加密算法,参考维基百科词条 Public-key cryptography。
公钥加密算法又称为非对称密钥加密算法,因为它包含一个公钥-私钥对,称为key pair。即 key pair = private key + public key。
从功能上说,两个key感化雷同,用一个key加密的消息,只能用另一个key解密,反之亦然。两个 key 的差别只在于谁拥有/知道它:private key 只有 key pair 的生成者知道,public key 则公开。key pair 的另一个特点是无法从一个 key 推算出另一个 key。
常用公钥加密算法是RSA和DSA。(TODO: 差别?)
(2)数字
关于数字,参考维基百科词条 Digital signature。
数字算法是基于公钥加密算法的,其过程是:
- 生成 key pair
- :对消息进行择要获得其Hash值;用 private key 加密消息Hash获得数字(Signature)
- 验证:对消息进行择要获得其Hash值;用 public key 解开数字获得消息Hash;对两个Hash进行比对
因为 private key 无法捏造或从 public key 推算出,是以,消息发送者必为 private key 拥有者,由此确保了消息起原的真实性(Authentication)和不成否定性(Non-repudiation)。若是消息在发送过程中破坏或被批改,进行择要后Hash值必然不一致,数字验证无法经由过程,由此确保了消息内容的完全性(Integrity)。
(3)消息择要
关于消息择要,参考维基百科词条 Cryptographic hash function。
消息择要算法是应用一个Hash函数对随便率性长度的输入数据进行处理惩罚,输出固定长度的数据。输出数据称为消息择要。无法从消息择要倒推出消息内容。常用的消息择要算法是 MD5 和 SHA-1。(TODO: 差别?)
2,Jar 包和验证
对Jar包的数字和验证过程和前面描述的数字道理和过程一致。Jar包是待发送的消息,经过后,Jar包内置入了数字和public key,验证者可以应用这两项数据进行验证。
实际上,经的Jar包内包含了以下内容:
- 原Jar包内的class文件和资料文件
- 文件 META-INF/.SF:这是一个文本文件,包含原Jar包内的class文件和资料文件的Hash
- block文件 META-INF/.DSA:这是一个数据文件,包含者的 certificate 和数字。此中 certificate 包含了者的有关信息和 public key;数字是对 .SF 文件内的 Hash 值应用 private key 加密得来
(1)应用 keytool 和 jarsigner 对象进行 Jar 包和验证
JDK 供给了 keytool 和 jarsigner 两个对象用来进行 Jar 包和验证。
keytool 用来生成和经管 keystore。keystore 是一个数据文件,存储了 key pair 有关的2种数据:private key 和 certificate,而 certificate 包含了 public key。全部 keystore 用一个暗码进行保护,keystore 里面的每一对 key pair 零丁用一个暗码进行保护。每对 key pair 用一个 alias 进行指定,alias 不区分大小写。
keytool 支撑的算法是:
- 若是公钥算法为 DSA,则择要算法应用 SHA-1。这是默认的
- 若是公钥算法为 RSA,则择要算法采取 MD5
jarsigner 读取 keystore,为 Jar 包进行数字。jarsigner 也可以对的 Jar 包进行验证。
下面以 JDK 中的 tools.jar 包为例,应用 keytool 和 jarsigner 对它进行和验证。
第1步:用 keytool 生成 keystore
履行以下号令,生成文件名为 test.ks 的 keystore,并生成 alias 为 testkey 的 key pair
keytool -keystore test.ks -genkey -alias testkey
按照屏幕提示输入各项信息
输入keystore暗码:
再次输入新暗码:
您的名字与姓氏是什么?
[Unknown]:
您的组织单位名称是什么?
[Unknown]:
您的组织名称是什么?
[Unknown]:
您地点的城市或区域名称是什么?
[Unknown]:
您地点的州或省份名称是什么?
[Unknown]:
该单位的两字母国度代码是什么
[Unknown]:
CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown 正确吗?
[否]: y
输入<testkey>的主暗码
(若是和 keystore 暗码雷同,按回车):
再次输入新暗码:
第2步:用 jarsigner 对 Jar 包进行
履行号令并按提示输入 keystore 和 testkey 的暗码后,即可对 tools.jar 进行并输出为 tools_signed.jar
jarsigner -keystore test.ks -signedjar tools_signed.jar tools.jar testkey
输入密钥库的口令短语:
输入 testkey 的密钥口令:
警告:
者将在六个月内过期。
第3步:用 jarsigner 对 Jar 包进行验证
履行以下号令,验证Jar 包是否有效
jarsigner -verify tools_signed.jar
输出
jar 已验证。
警告:
此 jar 包含者将在六个月内过期的条目。
要懂得具体信息,请应用 -verbose 和 -certs 选项从头运行。
重视,以上号令只是应用 Jar 包内的文件,验证 public key 与生成的 private key 是否是有效 key pair,以及 Jar 包内容是否完全,并没有和 keystore 进行比对。若是须要验证 Jar 包是否是应用某一 keystore 内的密钥进行的,可以指定如下的号令和选项:
jarsigner -verify -verbose -keystore test.ks tools_signed.j
ar
输出如下,重视对每一个class或资料文件,前面状况标识表记标帜中包含k,注解在 keystore 中找到了匹配的 certificate,也就是找到了匹配的 public key。若是须要打印出每一个 class文件或资料文件的 certificate 具体信息,可以增长 -certs 选项
...
smk 3384 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/HotSpotAttachProvider.class
smk 4597 Tue Jul 19 01:52:50 CST 2011 sun/tools/attach/HotSpotVirtualMachine.class
smk 3487 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsAttachProvider.class
smk 1001 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsVirtualMachine¥PipedInputStream.class
smk 2796 Tue Jul 19 02:02:54 CST 2011 sun/tools/attach/WindowsVirtualMachine.class
0 Tue Jul 19 01:52:50 CST 2011 sun/tools/jstack/
smk 4113 Tue Jul 19 01:52:50 CST 2011 sun/tools/jstack/JStack.class
0 Tue Jul 19 01:53:02 CST 2011 sun/tools/jinfo/
smk 4325 Tue Jul 19 01:53:02 CST 2011 sun/tools/jinfo/JInfo.class
0 Tue Jul 19 01:52:56 CST 2011 sun/tools/jmap/
smk 8177 Tue Jul 19 01:52:56 CST 2011 sun/tools/jmap/JMap.class
s = 已验证
m = 在清单中列出条目
k = 在密钥库中至少找到了一个
i = 在身份感化域内至少找到了一个
jar 已验证。
警告:
此 jar 包含者将在六个月内过期的条目。
要懂得具体信息,请应用 -verbose 和 -certs 选项从头运行。
(2)编程进行 Jar 包的验证
可以应用以下API在运行时对 Jar 包进行验证:
- java.util.jar.JarFile
- java.util.jar.JarEntry
- java.security.KeyStore
- java.security.cert.Certificate
读取 keystore 内的 certificate:
final String ksPath = ...
final String ksPass = ...
final HashMap<String, Certificate> certMap = new HashMap<String, Certificate>();
InputStream in = new FileInputStream(ksPath);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, ksPass.toCharArray());
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate cert = s.getCertificate(alias);
certMap.put(alias, cert);
}// while
验证 Jar 包:
final String jarPath = G:\\tmp\\jar_sign_test\\tools_signed.jar;
JarFile jar = new JarFile(jarPath, true);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
// Verify the entry
InputStream in = jar.getInputStream(entry);
try {
drain(in);
} finally {
try {
in.close();
} catch (Exception e) {
}
}
Certificate[] certs = entry.getCertificates();
if (null != certs && certs.length > 0) {
for (Certificate cert : certs) {
String alias = verify(cert, certMap);
if (null == alias) {
...
} else {
...
}
}// for
}
} // while
按照 JarEntry.getCertificates() 办法 Java doc,在调用之前,必须起首将此 JarEntry 数据完全读取,是以上方的代码段中调用了一个 drain() 办法:
private static void drain(InputStream in) throws IOException {
byte[] buf = new byte[512];
while (-1 != in.read(buf))
;
}
verify() 办法用来搜检 certificate 是否与 keystore 内的某个 certificate 匹配,首要用到了 Certificate.verify(PublicKey ) 办法:
private static String verify(Certificate cert, HashMap<String, Certificate> map) {
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String alias = it.next();
try {
cert.verify(map.get(alias).getPublicKey());
return alias;
} catch (Exception e) {
continue;
}
}// while
return null;
}
我们永远不要期待别人的拯救,只有自己才能升华自己。自己已准备好了多少容量,方能吸引对等的人与我们相遇,否则再美好的人出现、再动人的事情降临身边,我们也没有能量去理解与珍惜,终将擦肩而过。—— 姚谦《品味》