原文地址: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下载的文件截成块,分块之后进行摘要,通过摘要来验证所文件的最终的完整性,如果不完整是解压不开的。



算法摘要长度实现方
MD2128JDK
MD4128Bouncy Castle
MD5128JDK


[java] view plain <http://blog.csdn.net/u013991521/article/details/48193953#> 
copy <http://blog.csdn.net/u013991521/article/details/48193953#>
* package com.timliu.security.message_digest;  
*   
* import java.security.MessageDigest;  
* import java.security.Security;  
*   
* import org.apache.commons.codec.binary.Hex;  
* import org.apache.commons.codec.digest.DigestUtils;  
* import org.bouncycastle.crypto.digests.MD2Digest;  
* import org.bouncycastle.crypto.digests.MD4Digest;  
* import org.bouncycastle.crypto.digests.MD5Digest;  
* import org.bouncycastle.jce.provider.BouncyCastleProvider;  
*   
* public class MD5Test {  
*   
*     public static final String src = "hello world";  
*   
*     public static void main(String[] args) {  
*         jdkMD5();  
*         jdkMD2();  
*   
*         bcMD4();  
*         bcMD5();  
*   
*         bc2jdkMD4();  
*   
*         ccMD5();  
*         ccMD2();  
*   
*     }  
*   
*     // 用jdk实现:MD5  
*     public static void jdkMD5() {  
*         try {  
*             MessageDigest md = MessageDigest.getInstance("MD5");
// 得到MD5加密的对象  
*             byte[] md5Bytes = md.digest(src.getBytes());  
*             System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));
// Hex.encodeHexString()将byte[]数组转换成十六进制  
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用jdk实现:MD2  
*     public static void jdkMD2() {  
*         try {  
*             MessageDigest md = MessageDigest.getInstance("MD2");  
*             byte[] md2Bytes = md.digest(src.getBytes());  
*             System.out.println("JDK MD2:"
 + Hex.encodeHexString(md2Bytes));  
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用bouncy castle实现:MD5  
*     public static void bcMD5() {  
*         MD5Digest digest = new MD5Digest();  
*         digest.update(src.getBytes(), 0, src.getBytes().length);  
*         byte[] md5Bytes = new byte[digest.getDigestSize()];  
*         digest.doFinal(md5Bytes, 0);  
*         System.out.println("bouncy castle MD5:"  
*
                + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));  
*   
*     }  
*   
*     // 用bouncy castle实现:MD4  
*     public static void bcMD4() {  
*         MD4Digest digest = new MD4Digest();  
*         digest.update(src.getBytes(), 0, src.getBytes().length);  
*         byte[] md4Bytes = new byte[digest.getDigestSize()];  
*         digest.doFinal(md4Bytes, 0);  
*         System.out.println("bouncy castle MD4:"  
*
                + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));  
*     }  
*   
*     // 用bouncy castle与jdk结合实现:MD4  
*     public static void bc2jdkMD4() {  
*         try {  
*             Security.addProvider(new BouncyCastleProvider());  
*             MessageDigest md = MessageDigest.getInstance("MD4");  
*             byte[] md4Bytes = md.digest(src.getBytes());  
*             System.out.println("bc and JDK MD4:"  
*                     + Hex.encodeHexString(md4Bytes));  
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用common codes实现实现:MD5  
*     public static void ccMD5() {  
*         System.out.println("common codes MD5:"  
*                 + DigestUtils.md5Hex(src.getBytes()));  
*     }  
*   
*     // 用common codes实现实现:MD2  
*     public static void ccMD2() {  
*         System.out.println("common codes MD2:"  
*                 + DigestUtils.md2Hex(src.getBytes()));  
*     }  
*   
* }  运行结果:








分析上边的代码:

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-1160JDK
SHA-224224Bouncy Castle
SHA-256
256JDK
SHA-384384JDK
SHA-512512JDK
例子:



[java] view plain <http://blog.csdn.net/u013991521/article/details/48193953#> 
copy <http://blog.csdn.net/u013991521/article/details/48193953#>
* package com.timliu.security.message_digest;  
*   
* import java.security.MessageDigest;  
* import java.security.Security;  
*   
* import org.apache.commons.codec.binary.Hex;  
* import org.apache.commons.codec.digest.DigestUtils;  
* import org.bouncycastle.crypto.Digest;  
* import org.bouncycastle.crypto.digests.SHA1Digest;  
* import org.bouncycastle.crypto.digests.SHA224Digest;  
* import org.bouncycastle.jce.provider.BouncyCastleProvider;  
*   
* public class SHATest {  
*     public static final String src = "hello world";  
*   
*     public static void main(String[] args) {  
*         jdkSHA1();  
*         bcSHA1();  
*         bcSHA224();  
*         bcSHA224b();  
*         ccSHA1();  
*   
*     }  
*   
*     // 用jdk实现:SHA1  
*     public static void jdkSHA1() {  
*         try {  
*             // SHA-1的名称就是SHA  
*             MessageDigest md = MessageDigest.getInstance("SHA");  
*             md.update(src.getBytes());  
*             System.out.println("jdk sha-1:"
 + Hex.encodeHexString(md.digest()));  
*   
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用bouncy castle实现:SHA1  
*     public static void bcSHA1() {  
*   
*         Digest digest = new SHA1Digest();  
*         digest.update(src.getBytes(), 0, src.getBytes().length);  
*         byte[] sha1Bytes = new byte[digest.getDigestSize()];  
*         digest.doFinal(sha1Bytes, 0);  
*         System.out.println("bc sha-1:"  
*
                + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));  
*     }  
*   
*     // 用bouncy castle实现:SHA224  
*     public static void bcSHA224() {  
*   
*         Digest digest = new SHA224Digest();  
*         digest.update(src.getBytes(), 0, src.getBytes().length);  
*         byte[] sha224Bytes = new byte[digest.getDigestSize()];  
*         digest.doFinal(sha224Bytes, 0);  
*         System.out.println("bc sha-224:"  
*
                + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));  
*     }  
*   
*     // 用bouncy castle与jdk结合实现:SHA224  
*     public static void bcSHA224b() {  
*   
*         try {  
*             Security.addProvider(new BouncyCastleProvider());  
*             MessageDigest md = MessageDigest.getInstance("SHA224");  
*             md.update(src.getBytes());  
*             System.out.println("bc and JDK sha-224:"  
*                     + Hex.encodeHexString(md.digest()));  
*   
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用common codes实现实现:SHA1  
*     public static void ccSHA1() {  
*         //byte[]数组方式  
*         System.out.println("common codes SHA1 - 1 :"  
*                 + DigestUtils.sha1Hex(src.getBytes()));  
*         //String方式  
*         System.out  
*                 .println("common codes SHA1 - 2 :"
 + DigestUtils.sha1Hex(src));  
*     }  
*   
* }  运行结果:






分析上边的代码:

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×tamp=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






算法摘要长度实现方
HmacMD2128Bouncy Castle
HmacMD4
128Bouncy Castle

HmacMD5
128JDK
HmacSHA1160JDK

HmacSHA224224Bouncy Castle

HmacSHA256
256JDK

HmacSHA384
384JDK

HmacSHA512
512JDK



例子:


[java] view plain <http://blog.csdn.net/u013991521/article/details/48193953#> 
copy <http://blog.csdn.net/u013991521/article/details/48193953#>
* package com.timliu.security.message_digest;  
*   
* import javax.crypto.KeyGenerator;  
* import javax.crypto.Mac;  
* import javax.crypto.SecretKey;  
* import javax.crypto.spec.SecretKeySpec;  
*   
* import org.apache.commons.codec.binary.Hex;  
* import org.bouncycastle.crypto.digests.MD5Digest;  
* import org.bouncycastle.crypto.macs.HMac;  
* import org.bouncycastle.crypto.params.KeyParameter;  
*   
* public class HMACTest {  
*     public static final String src = "hello world";  
*   
*     public static void main(String[] args) {  
*         jdkHmacMD5();  
*         bcHmacMD5();  
*   
*     }  
*   
*     // 用jdk实现:  
*     public static void jdkHmacMD5() {  
*         try {  
*             // 初始化KeyGenerator  
*             KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"
);  
*             // 产生密钥  
*             SecretKey secretKey = keyGenerator.generateKey();  
*             // 获取密钥  
*             // byte[] key = secretKey.getEncoded();  
*             byte[] key = Hex.decodeHex(new char[] { '1', '2', '3', '4', '5'
,  
*                     '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e' });  
*   
*             // 还原密钥,HmacMD5是算法的名字  
*             SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5"
);  
*             // 实例化MAC  
*             Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());  
*             // 初始化MAC  
*             mac.init(restoreSecretKey);  
*             // 执行消息摘要  
*             byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());  
*             System.out.println("jdk hmacMD5:"  
*                     + Hex.encodeHexString(hmacMD5Bytes));  
*   
*         } catch (Exception e) {  
*             e.printStackTrace();  
*         }  
*     }  
*   
*     // 用bouncy castle实现:  
*     public static void bcHmacMD5() {  
*         HMac hmac = new HMac(new MD5Digest());  
*         // 必须是16进制的字符,长度必须是2的倍数  
*         hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex  
*                 .decode("123456789abcde")));  
*         hmac.update(src.getBytes(), 0, src.getBytes().length);  
*   
*         // 执行摘要  
*         byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];  
*         hmac.doFinal(hmacMD5Bytes, 0);  
*         System.out.println("bc hmacMD5:"  
*
                + org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5Bytes));  
*   
*     }  
*   
* }  
运行结果:





代码分析:

使用jdk实现的方式中:


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





用bouncy castle实现的方式中:



[java] view plain <http://blog.csdn.net/u013991521/article/details/48193953#> 
copy <http://blog.csdn.net/u013991521/article/details/48193953#>
* // 必须是16进制的字符,长度必须是2的倍数  
*         hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex  
*                 .decode("123456789abcde")));  
这里的Hex.decode()也是自己设定的密钥的来源。注意:来源必须是16进制的字符,长度必须是2的倍数。





HMAC算法的应用:


友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信