三种摘要算法的简单介绍

原文地址:http://blog.csdn.net/u013991521/article/details/48193953

介绍:

消息摘要算法分为三类

MD(Message Digest):消息摘要

SHA(Secure Hash Algorithm):安全散列

MAC(Message Authentication Code):消息认证码


这三类算法的主要作用:验证数据的完整性

消息摘要算法是有关于数字签名的核心算法。


MD算法:

MD算法家族:

生成的消息摘要都是128位的。

包括:MD2,MD4,MD5

从安全性上说:MD5 > MD4 > MD2

应用举例

电驴(点对点的下载工具)使用的是经过改良的MD4的算法,这种改良后的MD4算法主要是用于通过P2P下载的文件截成块,分块之后进行摘要,通过摘要来验证所文件的最终的完整性,如果不完整是解压不开的。

算法 摘要长度 实现方
MD2 128 JDK
MD4 128 Bouncy Castle
MD5 128 JDK

[java]  view plain  copy
  1. package com.timliu.security.message_digest;  
  2.   
  3. import java.security.MessageDigest;  
  4. import java.security.Security;  
  5.   
  6. import org.apache.commons.codec.binary.Hex;  
  7. import org.apache.commons.codec.digest.DigestUtils;  
  8. import org.bouncycastle.crypto.digests.MD2Digest;  
  9. import org.bouncycastle.crypto.digests.MD4Digest;  
  10. import org.bouncycastle.crypto.digests.MD5Digest;  
  11. import org.bouncycastle.jce.provider.BouncyCastleProvider;  
  12.   
  13. public class MD5Test {  
  14.   
  15.     public static final String src = "hello world";  
  16.   
  17.     public static void main(String[] args) {  
  18.         jdkMD5();  
  19.         jdkMD2();  
  20.   
  21.         bcMD4();  
  22.         bcMD5();  
  23.   
  24.         bc2jdkMD4();  
  25.   
  26.         ccMD5();  
  27.         ccMD2();  
  28.   
  29.     }  
  30.   
  31.     // 用jdk实现:MD5  
  32.     public static void jdkMD5() {  
  33.         try {  
  34.             MessageDigest md = MessageDigest.getInstance("MD5");// 得到MD5加密的对象  
  35.             byte[] md5Bytes = md.digest(src.getBytes());  
  36.             System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));// Hex.encodeHexString()将byte[]数组转换成十六进制  
  37.         } catch (Exception e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41.   
  42.     // 用jdk实现:MD2  
  43.     public static void jdkMD2() {  
  44.         try {  
  45.             MessageDigest md = MessageDigest.getInstance("MD2");  
  46.             byte[] md2Bytes = md.digest(src.getBytes());  
  47.             System.out.println("JDK MD2:" + Hex.encodeHexString(md2Bytes));  
  48.         } catch (Exception e) {  
  49.             e.printStackTrace();  
  50.         }  
  51.     }  
  52.   
  53.     // 用bouncy castle实现:MD5  
  54.     public static void bcMD5() {  
  55.         MD5Digest digest = new MD5Digest();  
  56.         digest.update(src.getBytes(), 0, src.getBytes().length);  
  57.         byte[] md5Bytes = new byte[digest.getDigestSize()];  
  58.         digest.doFinal(md5Bytes, 0);  
  59.         System.out.println("bouncy castle MD5:"  
  60.                 + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));  
  61.   
  62.     }  
  63.   
  64.     // 用bouncy castle实现:MD4  
  65.     public static void bcMD4() {  
  66.         MD4Digest digest = new MD4Digest();  
  67.         digest.update(src.getBytes(), 0, src.getBytes().length);  
  68.         byte[] md4Bytes = new byte[digest.getDigestSize()];  
  69.         digest.doFinal(md4Bytes, 0);  
  70.         System.out.println("bouncy castle MD4:"  
  71.                 + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));  
  72.     }  
  73.   
  74.     // 用bouncy castle与jdk结合实现:MD4  
  75.     public static void bc2jdkMD4() {  
  76.         try {  
  77.             Security.addProvider(new BouncyCastleProvider());  
  78.             MessageDigest md = MessageDigest.getInstance("MD4");  
  79.             byte[] md4Bytes = md.digest(src.getBytes());  
  80.             System.out.println("bc and JDK MD4:"  
  81.                     + Hex.encodeHexString(md4Bytes));  
  82.         } catch (Exception e) {  
  83.             e.printStackTrace();  
  84.         }  
  85.     }  
  86.   
  87.     // 用common codes实现实现:MD5  
  88.     public static void ccMD5() {  
  89.         System.out.println("common codes MD5:"  
  90.                 + DigestUtils.md5Hex(src.getBytes()));  
  91.     }  
  92.   
  93.     // 用common codes实现实现:MD2  
  94.     public static void ccMD2() {  
  95.         System.out.println("common codes MD2:"  
  96.                 + DigestUtils.md2Hex(src.getBytes()));  
  97.     }  
  98.   
  99. }  
运行结果:



分析上边的代码:

bouncy castle提供了MD4,MD5,MD2的实现

common codes只是对JDK中MD5,MD2的实现进行了简化

JDK提供的MD5,MD2的实现偏底层一些,缺少了相应的进制的转换。比如,将byte[]数组转换为十六进制


MD5算法的应用:



上边是简单的用户注册,登录一个系统的过程分析图。

注册时,系统会将用户的密码进行消息摘要(如MD5),然后将用户名和密码保存到数据库中。

登录时,系统会将用户输入的密码进行消息摘要(如MD5),然后将输入的用户名和加密后的密码与数据库中的进行比对,判断是否正确。


SHA算法:

介绍:

安全散列算法

固定长度摘要信息

包括:SHA-1,SHA-2(SHA-224,SHA-256,SHA-384,SHA-512)

算法 摘要长度 实现方
SHA-1 160 JDK
SHA-224 224 Bouncy Castle
SHA-256
256 JDK
SHA-384 384 JDK
SHA-512 512 JDK

例子:

[java]  view plain  copy
  1. package com.timliu.security.message_digest;  
  2.   
  3. import java.security.MessageDigest;  
  4. import java.security.Security;  
  5.   
  6. import org.apache.commons.codec.binary.Hex;  
  7. import org.apache.commons.codec.digest.DigestUtils;  
  8. import org.bouncycastle.crypto.Digest;  
  9. import org.bouncycastle.crypto.digests.SHA1Digest;  
  10. import org.bouncycastle.crypto.digests.SHA224Digest;  
  11. import org.bouncycastle.jce.provider.BouncyCastleProvider;  
  12.   
  13. public class SHATest {  
  14.     public static final String src = "hello world";  
  15.   
  16.     public static void main(String[] args) {  
  17.         jdkSHA1();  
  18.         bcSHA1();  
  19.         bcSHA224();  
  20.         bcSHA224b();  
  21.         ccSHA1();  
  22.   
  23.     }  
  24.   
  25.     // 用jdk实现:SHA1  
  26.     public static void jdkSHA1() {  
  27.         try {  
  28.             // SHA-1的名称就是SHA  
  29.             MessageDigest md = MessageDigest.getInstance("SHA");  
  30.             md.update(src.getBytes());  
  31.             System.out.println("jdk sha-1:" + Hex.encodeHexString(md.digest()));  
  32.   
  33.         } catch (Exception e) {  
  34.             e.printStackTrace();  
  35.         }  
  36.     }  
  37.   
  38.     // 用bouncy castle实现:SHA1  
  39.     public static void bcSHA1() {  
  40.   
  41.         Digest digest = new SHA1Digest();  
  42.         digest.update(src.getBytes(), 0, src.getBytes().length);  
  43.         byte[] sha1Bytes = new byte[digest.getDigestSize()];  
  44.         digest.doFinal(sha1Bytes, 0);  
  45.         System.out.println("bc sha-1:"  
  46.                 + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));  
  47.     }  
  48.   
  49.     // 用bouncy castle实现:SHA224  
  50.     public static void bcSHA224() {  
  51.   
  52.         Digest digest = new SHA224Digest();  
  53.         digest.update(src.getBytes(), 0, src.getBytes().length);  
  54.         byte[] sha224Bytes = new byte[digest.getDigestSize()];  
  55.         digest.doFinal(sha224Bytes, 0);  
  56.         System.out.println("bc sha-224:"  
  57.                 + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));  
  58.     }  
  59.   
  60.     // 用bouncy castle与jdk结合实现:SHA224  
  61.     public static void bcSHA224b() {  
  62.   
  63.         try {  
  64.             Security.addProvider(new BouncyCastleProvider());  
  65.             MessageDigest md = MessageDigest.getInstance("SHA224");  
  66.             md.update(src.getBytes());  
  67.             System.out.println("bc and JDK sha-224:"  
  68.                     + Hex.encodeHexString(md.digest()));  
  69.   
  70.         } catch (Exception e) {  
  71.             e.printStackTrace();  
  72.         }  
  73.     }  
  74.   
  75.     // 用common codes实现实现:SHA1  
  76.     public static void ccSHA1() {  
  77.         //byte[]数组方式  
  78.         System.out.println("common codes SHA1 - 1 :"  
  79.                 + DigestUtils.sha1Hex(src.getBytes()));  
  80.         //String方式  
  81.         System.out  
  82.                 .println("common codes SHA1 - 2 :" + DigestUtils.sha1Hex(src));  
  83.     }  
  84.   
  85. }  
运行结果:



分析上边的代码:

bouncy castle提供了所有的SHA消息摘要算法,其中SHA-224消息摘要算法是JDK中没有提供的。

common codes只是对JDK提供的SHA消息摘要算法进行了简化。


SHA算法的应用


分析上图:

第三步和第四步是发送方将已经对消息进行SHA算法处理的消息摘要和原始的消息发送给接收方,接收方对消息进行鉴别。

消息鉴别是指接收方将原始信息进行摘要,然后与接收到的摘要信息进行比对,判断接收方接收到的消息是否是发送方发送的最原始的消息。


比如QQ的联合登陆,就是使用QQ号码登陆其他的网站需要这些过程(但是这个例子不局限与SHA算法加密):

1.在消息内容中加入约定的Key(QQ会给接入方一个Key)

2.增加时间戳(QQ会约定一个消息传递的格式)

3.排序(对消息按照一定的格式进行排序(如:msg:原始消息+key+时间戳),然后对消息进行算法摘要)

4.将摘要后的信息发送给接收方

5.接收方再按照上面的规则进行操作

http://**?msg=12Hsad74mj&timestamp=1309488734

msg是经过加密的摘要消息

timestamp是时间戳


MAC算法

介绍:

HMAC(keyed-Hash Message Authentication Code):含有密钥的散列函数算法

包含了MD和SHA两个系列的消息摘要算法

HMAC只是在原有的MD和SHA算法的基础上添加了密钥。

融合了MD,SHA:

MD系列:HmacMD2,HmacMD4,HmacMD5

SHA系列:HmacSHA1,HmacSHA224,HmacSHA256,HmacSHA38

,HmacSHA512


算法 摘要长度 实现方
HmacMD2 128 Bouncy Castle
HmacMD4
128 Bouncy Castle
HmacMD5
128 JDK
HmacSHA1 160 JDK
HmacSHA224 224 Bouncy Castle
HmacSHA256
256 JDK
HmacSHA384
384 JDK
HmacSHA512
512 JDK

例子:

[java]  view plain  copy
  1. package com.timliu.security.message_digest;  
  2.   
  3. import javax.crypto.KeyGenerator;  
  4. import javax.crypto.Mac;  
  5. import javax.crypto.SecretKey;  
  6. import javax.crypto.spec.SecretKeySpec;  
  7.   
  8. import org.apache.commons.codec.binary.Hex;  
  9. import org.bouncycastle.crypto.digests.MD5Digest;  
  10. import org.bouncycastle.crypto.macs.HMac;  
  11. import org.bouncycastle.crypto.params.KeyParameter;  
  12.   
  13. public class HMACTest {  
  14.     public static final String src = "hello world";  
  15.   
  16.     public static void main(String[] args) {  
  17.         jdkHmacMD5();  
  18.         bcHmacMD5();  
  19.   
  20.     }  
  21.   
  22.     // 用jdk实现:  
  23.     public static void jdkHmacMD5() {  
  24.         try {  
  25.             // 初始化KeyGenerator  
  26.             KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");  
  27.             // 产生密钥  
  28.             SecretKey secretKey = keyGenerator.generateKey();  
  29.             // 获取密钥  
  30.             // byte[] key = secretKey.getEncoded();  
  31.             byte[] key = Hex.decodeHex(new char[] { '1''2''3''4''5',  
  32.                     '6''7''8''9''a''b''c''d''e' });  
  33.   
  34.             // 还原密钥,HmacMD5是算法的名字  
  35.             SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5");  
  36.             // 实例化MAC  
  37.             Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());  
  38.             // 初始化MAC  
  39.             mac.init(restoreSecretKey);  
  40.             // 执行消息摘要  
  41.             byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());  
  42.             System.out.println("jdk hmacMD5:"  
  43.                     + Hex.encodeHexString(hmacMD5Bytes));  
  44.   
  45.         } catch (Exception e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.     }  
  49.   
  50.     // 用bouncy castle实现:  
  51.     public static void bcHmacMD5() {  
  52.         HMac hmac = new HMac(new MD5Digest());  
  53.         // 必须是16进制的字符,长度必须是2的倍数  
  54.         hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex  
  55.                 .decode("123456789abcde")));  
  56.         hmac.update(src.getBytes(), 0, src.getBytes().length);  
  57.   
  58.         // 执行摘要  
  59.         byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];  
  60.         hmac.doFinal(hmacMD5Bytes, 0);  
  61.         System.out.println("bc hmacMD5:"  
  62.                 + org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5Bytes));  
  63.   
  64.     }  
  65.   
  66. }  

运行结果:


代码分析:

使用jdk实现的方式中:

[java]  view plain  copy
  1. // 获取密钥  
  2. // byte[] key = secretKey.getEncoded();  
  3. byte[] key = Hex.decodeHex(new char[] { '1''2''3''4''5',  
  4.                     '6''7''8''9''a''b''c''d''e' });  
这里的第一个是getEncoded()是自己生成的。 Hex.decodeHex()可以自己设定密钥的来源。


用bouncy castle实现的方式中:

[java]  view plain  copy
  1. // 必须是16进制的字符,长度必须是2的倍数  
  2.         hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex  
  3.                 .decode("123456789abcde")));  

这里的Hex.decode()也是自己设定的密钥的来源。注意:来源必须是16进制的字符,长度必须是2的倍数。


HMAC算法的应用: