第 2 章在 JAVA 中的实现
2.1. 相关
Diffie-Hellman 密钥一致协议和 DES 程序需要 JCE 工具库的支持 , 可以到 http://java.sun.com/security/index.html 下载 JCE, 并进行安装。简易安装把 jce1.2.1\lib 下的所有内容复制到 %java_home%\lib\ext 下 , 如果没有 ext 目录自行建立 , 再把 jce1_2_1.jar 和 sunjce_provider.jar 添加到 CLASSPATH 内 , 更详细说明请看相应用户手册
2.2. 消息摘要 MD5 和 SHA 的使用
使用方法 :
首先用生成一个 MessageDigest 类 , 确定计算方法
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
添加要进行计算摘要的信息
alga.update(myinfo.getBytes());
计算出摘要
byte[] digesta=alga.digest();
发送给其他人你的信息和摘要
其他人用相同的方法初始化 , 添加信息 , 最后进行比较摘要是否相同
algb.isEqual(digesta,algb.digest())
相关 AIP
java.security.MessageDigest 类
static getInstance(String algorithm)
返回一个 MessageDigest 对象 , 它实现指定的算法
参数 : 算法名 , 如 SHA-1 或 MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
添加要进行计算摘要的信息
byte[] digest()
完成计算 , 返回计算得到的摘要 ( 对于 MD5 是 16 位 ,SHA 是 20 位 )
void reset()
复位
static boolean isEqual(byte[] digesta, byte[] digestb)
比效两个摘要是否相同
代码:
import java.security.*;
public class myDigest {
public static void main(String[] args) {
myDigest my=new myDigest();
my.testDigest();
}
public void testDigest()
{
try {
String myinfo="我的测试信息";
//java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5");
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
alga.update(myinfo.getBytes());
byte[] digesta=alga.digest();
System.out.println("本信息摘要是 :"+byte2hex(digesta));
// 通过某中方式传给其他人你的信息 (myinfo) 和摘要 (digesta) 对方可以判断是否更改或传输正常
java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1");
algb.update(myinfo.getBytes());
if (algb.isEqual(digesta,algb.digest())) {
System.out.println("信息检查正常");
}
else
{
System.out.println("摘要不相同");
}
}
catch (java.security.NoSuchAlgorithmException ex) {
System.out.println("非法摘要算法");
}
}
public String byte2hex(byte[] b) // 二行制转字符串
{
String hs="";
String stmp="";
for (int n=0;n<b.length;n++)
{
stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length()==1) hs=hs+"0"+stmp;
else hs=hs+stmp;
if (n<b.length-1) hs=hs+":";
}
return hs.toUpperCase();
}
}
2.3. 数字签名 DSA
1.对于一个用户来讲首先要生成他的密钥对 , 并且分别保存
生成一个 KeyPairGenerator 实例
java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA");
//如果设定随机产生器就用如相代码初始化
SecureRandom secrand=new SecureRandom();
secrand.setSeed("tttt".getBytes()); // 初始化随机产生器
keygen.initialize(512,secrand); // 初始化密钥生成器
//否则
keygen.initialize(512);
//生成密钥公钥 pubkey 和私钥 prikey
KeyPair keys=keygen.generateKeyPair(); // 生成密钥组
PublicKey pubkey=keys.getPublic();
PrivateKey prikey=keys.getPrivate();
//分别保存在 myprikey.dat 和 mypubkey.dat 中 , 以便下次不在生成
//( 生成密钥对的时间比较长
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(
new java.io.FileOutputStream("myprikey.dat"));
out.writeObject(prikey);
out.close();
out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
out.writeObject(pubkey);
out.close();
2.用他私人密钥 (prikey) 对他所确认的信息 (info) 进行数字签名产生一个签名数组
从文件中读入私人密钥 (prikey)
java.io.ObjectInputStream in=new java.io.ObjectInputStream(
new java.io.FileInputStream("myprikey.dat"));
PrivateKey myprikey=(PrivateKey)in.readObject();
in.close();
初始一个 Signature 对象 , 并用私钥对信息签名
java.security.Signature signet=java.security.Signature.getInstance("DSA");
signet.initSign(myprikey);
signet.update(myinfo.getBytes());
byte[] signed=signet.sign();
把信息和签名保存在一个文件中 (myinfo.dat)
java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(
new java.io.FileOutputStream("myinfo.dat"));
out.writeObject(myinfo);
out.writeObject(signed);
out.close();
把他的公钥的信息及签名发给其它用户
3.3.其他用户用他的公共密钥 (pubkey) 和签名 (signed) 和信息 (info) 进行验证是否由他签名的信息
读入公钥
java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
PublicKey pubkey=(PublicKey)in.readObject();
in.close();
读入签名和信息
in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
String info=(String)in.readObject();
byte[] signed=(byte[])in.readObject();
in.close();
初始一个 Signature 对象 , 并用公钥和签名进行验证
java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
signetcheck.initVerify(pubkey);
signetcheck.update(info.getBytes());
if (signetcheck.verify(signed)) { System.out.println("签名正常");}
对于密钥的保存本文是用对象流的方式保存和传送的 , 也可可以用编码的方式保存 . 注意要
import java.security.spec.*
import java.security.*
具休说明如下
public key 是用 X.509 编码的 , 例码如下 :
byte[] bobEncodedPubKey=mypublic.getEncoded(); // 生成编码
// 传送二进制编码
// 以下代码转换编码为相应 key 对象
X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
◦对于 Prbyte[] bPKCS=myprikey.getEncoded();
// 传送二进制编码
// 以下代码转换编码为相应 key 对象
PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);
KeyFactory keyf=KeyFactory.getInstance("DSA");
PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
ivate key 是用 PKCS#8 编码 , 例码如下 :
byte[] bPKCS=myprikey.getEncoded();
// 传送二进制编码
// 以下代码转换编码为相应 key 对象
PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);
KeyFactory keyf=KeyFactory.getInstance("DSA");
PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
4.4.常用 API
java.security.KeyPairGenerator 密钥生成器类
public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
以指定的算法返回一个 KeyPairGenerator 对象
参数 : algorithm 算法名 . 如 :"DSA","RSA"
public void initialize(int keysize)
以指定的长度初始化 KeyPairGenerator 对象 , 如果没有初始化系统以 1024 长度默认设置
参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间,且必须为 64 的倍数
public void initialize(int keysize, SecureRandom random)
以指定的长度初始化和随机发生器初始化 KeyPairGenerator 对象
参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间,且必须为 64 的倍数
random 一个随机位的来源 ( 对于 initialize(int keysize) 使用了默认随机器
public abstract KeyPair generateKeyPair()
产生新密钥对
java.security.KeyPair 密钥对类
public PrivateKey getPrivate()
返回私钥
public PublicKey getPublic()
返回公钥
java.security.Signature 签名类
public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
返回一个指定算法的 Signature 对象
参数 algorithm 如 :"DSA"
public final void initSign(PrivateKey privateKey)
throws InvalidKeyException
用指定的私钥初始化
参数 :privateKey 所进行签名时用的私钥
public final void update(byte data)
throws SignatureException
public final void update(byte[] data)
throws SignatureException
public final void update(byte[] data, int off, int len)
throws SignatureException
添加要签名的信息
public final byte[] sign()
throws SignatureException
返回签名的数组 , 前提是 initSign 和 update
public final void initVerify(PublicKey publicKey)
throws InvalidKeyException
用指定的公钥初始化
参数 :publicKey 验证时用的公钥
public final boolean verify(byte[] signature)
throws SignatureException
验证签名是否有效 , 前提是已经 initVerify 初始化
参数 : signature 签名数组
|