消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。 不同的消息获得的消息摘要各异,但相同的消息其消息摘要是唯一的。
public class TestMD5MessageDigest {
private static String str = "Hello,I sent to you 80 yuan.";
public static void main(String[] args) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes("UTF-8"));
byte[] re = md.digest();
System.out.println(re);
String result = "";
for (int i = 0; i < re.length; i++) {
result += Integer.toHexString((0x000000ff & re[i]) | 0xffffff00).substring(6);
}
System.out.println(result);
}
}
消息验证码
当一个文件和它的消息摘要一起从发送方传递到接收方时,接收方利用消息摘要验证数据,可以判断传输过程中有无修改过(判断完整性)。但是这样做的前提是消息摘要传输要正确无误。若传输过程中某人修改过文件,同时重新生成对应的消息摘要再传给对方,这样就无法验证是否原文被修改过,消息验证码就是用来解决这一问题。
消息通讯双方具有的共同密钥叫消息验证码。使用消息验证码的双方要有共同的密钥,发送方将消息摘要加密后发送,这样由于用密钥加密了消息摘要,无密钥难于修改消息摘要。接收方一定程度上可以验证发送方身份。javax.crypto包中的类Mac提供了计算消息摘要验证码的方法。
public class TestMD5MAC {
private static String message = "Hello World !";
public static void main(String[] args) {
byte[] bytes = message.getBytes("utf-8");
KeyGenerator ken = KeyGenerator.getInstance("DESede");
ken.init(168);
SecretKey key = ken.generateKey();
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update(bytes);
byte[] encryCodes = mac.doFinal();
System.out.println("============消息摘要验证码=============");
StringBuffer res = new StringBuffer();
for (int j = 0; j < encryCodes.length; j++) {
res.append(res);
res.append(Integer.toHexString((0x000000ff & encryCodes[j]) | 0xffffff00).substring(6));
}
System.out.println(res.toString());
System.out.println();
// 保存到文件中,以便验证消息摘要
FileOutputStream fos = new FileOutputStream("mac.dat");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(encryCodes);
}
}
数字签名
在java中完成数据签名的类是Signature。
public class TestSignature {
private static String str = "I'm live in china !";
public static void main(String[] args) {
byte[] bytes = str.getBytes("utf-8");
String str = new String(bytes);
System.out.println("==========要签名的原文===========");
System.out.println(str);
KeyPairGenerator ken = KeyPairGenerator.getInstance("RSA");
ken.initialize(1024);
KeyPair pair = ken.genKeyPair();
PrivateKey pri = pair.getPrivate();
Signature signer = Signature.getInstance("MD5withRSA");
//初始化私钥,若为公钥则使用initVeriry
signer.initSign(pri);
signer.update(bytes);
byte[] signs = signer.sign();
System.out.println("============签名=============");
for (int j = 0 ; j < signs.length ; j++) {
System.out.print(signs[j]);
if ((j % 8) == 7 ) {
System.out.println();
}
}
//保存签名到rsasign.sig
FileOutputStream fos = new FileOutputStream("rsasign.sig");
for (int j = 0 ; j < signs.length ; j++) {
fos.write(signs[j]);
}
fos.flush();
fos.close();
PublicKey pub = pair.getPublic();
RSAPublicKey rpub = (RSAPublicKey)pub;
byte [] kb = rpub.getEncoded();
//保存公钥
FileOutputStream fos2 = new FileOutputStream("rsapub.dat");
fos2.write(kb);
fos2.close();
signer.initVerify(rpub);
signer.update(bytes);
boolean ok = false;
FileInputStream fis = new FileInputStream("rsasign.sig");
int num = fis.available();
byte [] bytes2 = new byte[num];
fis.read(bytes2);
ok = signer.verify(bytes2);
System.out.println("签名验证结果 :"+ok);
}
}
<<To Be Continued>>