Java 加密解密之消息摘要算法(MD5 SHA MAC)
消息摘要
消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash 函数将需加密的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。
HASH函数的抗冲突性使得如果一段明文稍有变化,哪怕只更改该段落的一个字母,通过哈希算法作用后都将产生不同的值。而HASH算法的单向性使得要找到到哈希值相同的两个不同的输入消息,在计算上是不可能的。所以数据的哈希值,即消息摘要,可以检验数据的完整性。哈希函数的这种对不同的输入能够生成不同的值的特性使得无法找到两个具有相同哈希值的输入。因此,如果两个文档经哈希转换后成为相同的值,就可以肯定它们是同一文档。所以,当希望有效地比较两个数据块时,就可以比较它们的哈希值。例如,可以通过比较邮件发送前和发送后的哈希值来验证该邮件在传递时是否修改。
消息摘要算法
消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在密钥的管理与分发问题,适合于分布式网络相同上使用。由于其加密计算的工作量相当可观,所以以前的这种算法通常只用于数据量有限的情况下的加密,例如计算机的口令就是用不可逆加密算法加密的。近年来,随着计算机相同性能的飞速改善,加密速度不再成为限制这种加密技术发展的桎梏,因而消息摘要算法应用的领域不断增加。
消息摘要算法的特点:
① 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。
② 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。
③ 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。
④ 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。
⑤ 好的摘要算法,无法找到两条消息,是它们的摘要相同。
现有的消息摘要算法
消息摘要算法包含MD、SHA和MAC三大系列,常用于验证数据的完整性,是数据签名算法的核心算法。
MAC与MD和SHA不同,MAC是含有密钥的散列函数算法,我们也常把MAC称为HMAC。
JDK对消息摘要算法的支持
JDK6支持MD2/MD5/SHA/SHA256/SHA384/SHA512/HmacMD5/HmacSHA1/ HmacSHA256/HmacSHA384/HmacSHA512
使用到十六进制工具类Hex.java 见:java byte数组与十六进制字符串互转
MD和SHA系列的java实现:
DigestUtils.java
- importjava.security.MessageDigest;
- importjava.security.NoSuchAlgorithmException;
- /**
- *referenceapachecommons<a
- *href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>
- *
- *supportMD2/MD5/SHA/SHA256/SHA384/SHA512
- *@authorAub
- *
- */
- publicclassDigestUtils{
- /**
- *根据给定摘要算法创建一个消息摘要实例
- *
- *@paramalgorithm
- *摘要算法名
- *@return消息摘要实例
- *@seeMessageDigest#getInstance(String)
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- staticMessageDigestgetDigest(Stringalgorithm){
- try{
- returnMessageDigest.getInstance(algorithm);
- }catch(NoSuchAlgorithmExceptione){
- thrownewRuntimeException(e.getMessage());
- }
- }
- /**
- *获取MD5消息摘要实例
- *
- *@returnMD5消息摘要实例
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticMessageDigestgetMd5Digest(){
- returngetDigest("MD5");
- }
- /**
- *获取SHA-1消息摘要实例
- *
- *@returnSHA-1消息摘要实例
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticMessageDigestgetShaDigest(){
- returngetDigest("SHA");
- }
- /**
- *获取SHA-256消息摘要实例
- *
- *@returnSHA-256消息摘要实例
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticMessageDigestgetSha256Digest(){
- returngetDigest("SHA-256");
- }
- /**
- *获取SHA-384消息摘要实例
- *
- *@returnSHA-384消息摘要实例
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticMessageDigestgetSha384Digest(){
- returngetDigest("SHA-384");
- }
- /**
- *获取SHA-512消息摘要实例
- *
- *@returnSHA-512消息摘要实例
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticMessageDigestgetSha512Digest(){
- returngetDigest("SHA-512");
- }
- /**
- *使用MD5消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeMD5(byte[]data){
- returngetMd5Digest().digest(data);
- }
- /**
- *使用MD5消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@return消息摘要(长度为32的十六进制字符串)
- */
- publicstaticStringencodeMD5Hex(byte[]data){
- returnHex.encodeHexStr(encodeMD5(data));
- }
- /**
- *使用SHA-1消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-1消息摘要(长度为20的字节数组)
- */
- publicstaticbyte[]encodeSHA(byte[]data){
- returngetShaDigest().digest(data);
- }
- /**
- *使用SHA-1消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-1消息摘要(长度为40的十六进制字符串)
- */
- publicstaticStringencodeSHAHex(byte[]data){
- returnHex.encodeHexStr(getShaDigest().digest(data));
- }
- /**
- *使用SHA-256消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-256消息摘要(长度为32的字节数组)
- */
- publicstaticbyte[]encodeSHA256(byte[]data){
- returngetSha256Digest().digest(data);
- }
- /**
- *使用SHA-256消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-256消息摘要(长度为64的十六进制字符串)
- */
- publicstaticStringencodeSHA256Hex(byte[]data){
- returnHex.encodeHexStr(encodeSHA256(data));
- }
- /**
- *使用SHA-384消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-384消息摘要(长度为43的字节数组)
- */
- publicstaticbyte[]encodeSHA384(byte[]data){
- returngetSha384Digest().digest(data);
- }
- /**
- *使用SHA-384消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-384消息摘要(长度为86的十六进制字符串)
- */
- publicstaticStringencodeSHA384Hex(byte[]data){
- returnHex.encodeHexStr(encodeSHA384(data));
- }
- /**
- *使用SHA-512消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-512消息摘要(长度为64的字节数组)
- */
- publicstaticbyte[]encodeSHA512(byte[]data){
- returngetSha512Digest().digest(data);
- }
- /**
- *使用SHA-512消息摘要算法计算消息摘要
- *
- *@paramdata
- *做消息摘要的数据
- *@returnSHA-512消息摘要(长度为128的十六进制字符串)
- */
- publicstaticStringencodeSHA512Hex(byte[]data){
- returnHex.encodeHexStr(encodeSHA512(data));
- }
- }
参考org.apache.commons.codec.digest.DigestUtils
下载地址:http://commons.apache.org/codec/download_codec.cgi
MAC系列的java实现
Hmac.java
- importjava.security.InvalidKeyException;
- importjava.security.Key;
- importjava.security.NoSuchAlgorithmException;
- importjavax.crypto.KeyGenerator;
- importjavax.crypto.Mac;
- importjavax.crypto.SecretKey;
- importjavax.crypto.spec.SecretKeySpec;
- /**
- *Hmac<br/>
- *algorithmHmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512
- *@authorAub
- */
- publicclassHmac{
- /**
- *根据给定密钥生成算法创建密钥
- *
- *@paramalgorithm
- *密钥算法
- *@return密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- privatestaticbyte[]getHmacKey(Stringalgorithm){
- //初始化KeyGenerator
- KeyGeneratorkeyGenerator=null;
- try{
- keyGenerator=KeyGenerator.getInstance(algorithm);
- }catch(NoSuchAlgorithmExceptione){
- thrownewRuntimeException(e.getMessage());
- }
- //产生密钥
- SecretKeysecretKey=keyGenerator.generateKey();
- //获得密钥
- returnsecretKey.getEncoded();
- }
- /**
- *获取HmaMD5的密钥
- *
- *@returnHmaMD5的密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- publicstaticbyte[]getHmaMD5key(){
- returngetHmacKey("HmacMD5");
- }
- /**
- *获取HmaSHA的密钥
- *
- *@returnHmaSHA的密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- publicstaticbyte[]getHmaSHAkey(){
- returngetHmacKey("HmacSHA1");
- }
- /**
- *获取HmaSHA256的密钥
- *
- *@returnHmaSHA256的密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- publicstaticbyte[]getHmaSHA256key(){
- returngetHmacKey("HmacSHA256");
- }
- /**
- *获取HmaSHA384的密钥
- *
- *@returnHmaSHA384的密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- publicstaticbyte[]getHmaSHA384key(){
- returngetHmacKey("HmacSHA384");
- }
- /**
- *获取HmaSHA512的密钥
- *
- *@returnHmaSHA384的密钥
- *@throwsRuntimeException
- *当{@linkjava.security.NoSuchAlgorithmException}发生时
- */
- publicstaticbyte[]getHmaSHA512key(){
- returngetHmacKey("HmacSHA512");
- }
- /**
- *转换密钥
- *
- *@paramkey二进制密钥
- *@paramalgorithm密钥算法
- *@return密钥
- */
- privatestaticKeytoKey(byte[]key,Stringalgorithm){
- //生成密钥
- returnnewSecretKeySpec(key,algorithm);
- }
- /**
- *使用HmacMD5消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacMD5(byte[]data,Keykey){
- Macmac=null;
- try{
- mac=Mac.getInstance("HmacMD5");
- mac.init(key);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }catch(InvalidKeyExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }
- returnmac.doFinal(data);
- }
- /**
- *使用HmacMD5消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacMD5(byte[]data,byte[]key){
- Keyk=toKey(key,"HmacMD5");
- returnencodeHmacMD5(data,k);
- }
- /**
- *使用HmacSHA消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA(byte[]data,Keykey){
- Macmac=null;
- try{
- mac=Mac.getInstance("HmacSHA1");
- mac.init(key);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }catch(InvalidKeyExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }
- returnmac.doFinal(data);
- }
- /**
- *使用HmacSHA消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA(byte[]data,byte[]key){
- Keyk=toKey(key,"HmacSHA1");
- returnencodeHmacSHA(data,k);
- }
- /**
- *使用HmacSHA256消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA256(byte[]data,Keykey){
- Macmac=null;
- try{
- mac=Mac.getInstance("HmacSHA256");
- mac.init(key);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }catch(InvalidKeyExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }
- returnmac.doFinal(data);
- }
- /**
- *使用HmacSHA256消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA256(byte[]data,byte[]key){
- Keyk=toKey(key,"HmacSHA256");
- returnencodeHmacSHA256(data,k);
- }
- /**
- *使用HmacSHA384消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA384(byte[]data,Keykey){
- Macmac=null;
- try{
- mac=Mac.getInstance("HmacSHA384");
- mac.init(key);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }catch(InvalidKeyExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }
- returnmac.doFinal(data);
- }
- /**
- *使用HmacSHA384消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA384(byte[]data,byte[]key){
- Keyk=toKey(key,"HmacSHA384");
- returnencodeHmacSHA384(data,k);
- }
- /**
- *使用HmacSHA512消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA512(byte[]data,Keykey){
- Macmac=null;
- try{
- mac=Mac.getInstance("HmacSHA512");
- mac.init(key);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }catch(InvalidKeyExceptione){
- e.printStackTrace();
- returnnewbyte[0];
- }
- returnmac.doFinal(data);
- }
- /**
- *使用HmacSHA512消息摘要算法计算消息摘要
- *
- *@paramdata做消息摘要的数据
- *@paramkey密钥
- *@return消息摘要(长度为16的字节数组)
- */
- publicstaticbyte[]encodeHmacSHA512(byte[]data,byte[]key){
- Keyk=toKey(key,"HmacSHA512");
- returnencodeHmacSHA512(data,k);
- }
- privatestaticStringshowByteArray(byte[]data){
- if(null==data){
- returnnull;
- }
- StringBuildersb=newStringBuilder("{");
- for(byteb:data){
- sb.append(b).append(",");
- }
- sb.deleteCharAt(sb.length()-1);
- sb.append("}");
- returnsb.toString();
- }
- publicstaticvoidmain(String[]args){
- //byte[]key=getHmaMD5key();
- //byte[]key=getHmaSHAkey();
- //byte[]key=getHmaSHA256key();
- //byte[]key=getHmaSHA384key();
- byte[]key=getHmaSHA512key();
- System.out.println("加密密钥:byte[]:"+showByteArray(key).length());
- Stringdata="Mac数据";
- System.out.println("加密前数据:string:"+data);
- System.out.println("加密前数据:byte[]:"+showByteArray(data.getBytes()));
- System.out.println();
- //byte[]encodeData=encodeHmacMD5(data.getBytes(),key);
- //byte[]encodeData=encodeHmacSHA(data.getBytes(),key);
- //byte[]encodeData=encodeHmacSHA256(data.getBytes(),key);
- //byte[]encodeData=encodeHmacSHA384(data.getBytes(),key);
- byte[]encodeData=encodeHmacSHA512(data.getBytes(),key);
- System.out.println("加密后数据:byte[]:"+showByteArray(encodeData).length());
- System.out.println("加密后数据:byte[]:"+encodeData.length);
- System.out.println("加密后数据:hexStr:"+Hex.encodeHexStr(encodeData));
- System.out.println();
- }
- }