JAVA   加密解密系列

Java 加密解密基础

Java byte数组与十六进制字符串互转

Java BASE64加密解密

Java 加密解密之消息摘要算法(MD5 SHA MAC)

Java 加密解密之对称加密算法DES

Java 加密解密之对称加密算法DESede

Java 加密解密之对称加密算法AES

Java 加密解密之对称加密算法PBE



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

Java代码:

 
  
  1. import java.security.MessageDigest;  

  2. import java.security.NoSuchAlgorithmException;  

  3. /**

  4. * reference apache commons <a

  5. * href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>

  6. *  

  7. * support MD2/MD5/SHA/SHA256/SHA384/SHA512

  8. * @author Aub

  9. *  

  10. */

  11. publicclass DigestUtils {  

  12. /**

  13.     * 根据给定摘要算法创建一个消息摘要实例

  14.     *  

  15.     * @param algorithm

  16.     *            摘要算法名

  17.     * @return 消息摘要实例

  18.     * @see MessageDigest#getInstance(String)

  19.     * @throws RuntimeException

  20.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  21.     */

  22. static MessageDigest getDigest(String algorithm) {  

  23. try {  

  24. return MessageDigest.getInstance(algorithm);  

  25.        } catch (NoSuchAlgorithmException e) {  

  26. thrownew RuntimeException(e.getMessage());  

  27.        }  

  28.    }  

  29. /**

  30.     * 获取 MD5 消息摘要实例

  31.     *  

  32.     * @return MD5 消息摘要实例

  33.     * @throws RuntimeException

  34.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  35.     */

  36. privatestatic MessageDigest getMd5Digest() {  

  37. return getDigest("MD5");  

  38.    }  

  39. /**

  40.     * 获取 SHA-1 消息摘要实例

  41.     *  

  42.     * @return SHA-1 消息摘要实例

  43.     * @throws RuntimeException

  44.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  45.     */

  46. privatestatic MessageDigest getShaDigest() {  

  47. return getDigest("SHA");  

  48.    }  

  49. /**

  50.     * 获取 SHA-256 消息摘要实例

  51.     *  

  52.     * @return SHA-256 消息摘要实例

  53.     * @throws RuntimeException

  54.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  55.     */

  56. privatestatic MessageDigest getSha256Digest() {  

  57. return getDigest("SHA-256");  

  58.    }  

  59. /**

  60.     * 获取 SHA-384 消息摘要实例

  61.     *  

  62.     * @return SHA-384 消息摘要实例

  63.     * @throws RuntimeException

  64.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  65.     */

  66. privatestatic MessageDigest getSha384Digest() {  

  67. return getDigest("SHA-384");  

  68.    }  

  69. /**

  70.     * 获取 SHA-512 消息摘要实例

  71.     *  

  72.     * @return SHA-512 消息摘要实例

  73.     * @throws RuntimeException

  74.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  75.     */

  76. privatestatic MessageDigest getSha512Digest() {  

  77. return getDigest("SHA-512");  

  78.    }  

  79. /**

  80.     * 使用MD5消息摘要算法计算消息摘要

  81.     *  

  82.     * @param data

  83.     *            做消息摘要的数据

  84.     * @return 消息摘要(长度为16的字节数组)

  85.     */

  86. publicstaticbyte[] encodeMD5(byte[] data) {  

  87. return getMd5Digest().digest(data);  

  88.    }  

  89. /**

  90.     * 使用MD5消息摘要算法计算消息摘要

  91.     *  

  92.     * @param data

  93.     *            做消息摘要的数据

  94.     * @return 消息摘要(长度为32的十六进制字符串)

  95.     */

  96. publicstatic String encodeMD5Hex(byte[] data) {  

  97. return Hex.encodeHexStr(encodeMD5(data));  

  98.    }  

  99. /**

  100.     * 使用SHA-1消息摘要算法计算消息摘要

  101.     *  

  102.     * @param data

  103.     *            做消息摘要的数据

  104.     * @return SHA-1消息摘要(长度为20的字节数组)

  105.     */

  106. publicstaticbyte[] encodeSHA(byte[] data) {  

  107. return getShaDigest().digest(data);  

  108.    }  

  109. /**

  110.     * 使用SHA-1消息摘要算法计算消息摘要

  111.     *  

  112.     * @param data

  113.     *            做消息摘要的数据

  114.     * @return SHA-1消息摘要(长度为40的十六进制字符串)

  115.     */

  116. publicstatic String encodeSHAHex(byte[] data) {  

  117. return Hex.encodeHexStr(getShaDigest().digest(data));  

  118.    }  

  119. /**

  120.     * 使用SHA-256消息摘要算法计算消息摘要

  121.     *  

  122.     * @param data

  123.     *            做消息摘要的数据

  124.     * @return SHA-256消息摘要(长度为32的字节数组)

  125.     */

  126. publicstaticbyte[] encodeSHA256(byte[] data) {  

  127. return getSha256Digest().digest(data);  

  128.    }  

  129. /**

  130.     * 使用SHA-256消息摘要算法计算消息摘要

  131.     *  

  132.     * @param data

  133.     *            做消息摘要的数据

  134.     * @return SHA-256消息摘要(长度为64的十六进制字符串)

  135.     */

  136. publicstatic String encodeSHA256Hex(byte[] data) {  

  137. return Hex.encodeHexStr(encodeSHA256(data));  

  138.    }  

  139. /**

  140.     * 使用SHA-384消息摘要算法计算消息摘要

  141.     *  

  142.     * @param data

  143.     *            做消息摘要的数据

  144.     * @return SHA-384消息摘要(长度为43的字节数组)

  145.     */

  146. publicstaticbyte[] encodeSHA384(byte[] data) {  

  147. return getSha384Digest().digest(data);  

  148.    }  

  149. /**

  150.     * 使用SHA-384消息摘要算法计算消息摘要

  151.     *  

  152.     * @param data

  153.     *            做消息摘要的数据

  154.     * @return SHA-384消息摘要(长度为86的十六进制字符串)

  155.     */

  156. publicstatic String encodeSHA384Hex(byte[] data) {  

  157. return Hex.encodeHexStr(encodeSHA384(data));  

  158.    }  

  159. /**

  160.     * 使用SHA-512消息摘要算法计算消息摘要

  161.     *  

  162.     * @param data

  163.     *            做消息摘要的数据

  164.     * @return SHA-512消息摘要(长度为64的字节数组)

  165.     */

  166. publicstaticbyte[] encodeSHA512(byte[] data) {  

  167. return getSha512Digest().digest(data);  

  168.    }  

  169. /**

  170.     * 使用SHA-512消息摘要算法计算消息摘要

  171.     *  

  172.     * @param data

  173.     *            做消息摘要的数据

  174.     * @return SHA-512消息摘要(长度为128的十六进制字符串)

  175.     */

  176. publicstatic String encodeSHA512Hex(byte[] data) {  

  177. return Hex.encodeHexStr(encodeSHA512(data));  

  178.    }  

  179. }  


参考 org.apache.commons.codec.digest.DigestUtils
下载地址:
http://commons.apache.org/codec/download_codec.cgi


MAC系列的java实现

Hmac.java

Java代码:

 
  
  1. import java.security.InvalidKeyException;  

  2. import java.security.Key;  

  3. import java.security.NoSuchAlgorithmException;  

  4. import javax.crypto.KeyGenerator;  

  5. import javax.crypto.Mac;  

  6. import javax.crypto.SecretKey;  

  7. import javax.crypto.spec.SecretKeySpec;  

  8. /**

  9. * Hmac<br/>

  10. * algorithm HmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512

  11. * @author Aub

  12. */

  13. publicclass Hmac {  

  14. /**

  15.     * 根据给定密钥生成算法创建密钥

  16.     *  

  17.     * @param algorithm

  18.     *            密钥算法

  19.     * @return 密钥

  20.     * @throws RuntimeException

  21.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  22.     */

  23. privatestaticbyte[] getHmacKey(String algorithm){  

  24. //初始化KeyGenerator  

  25.        KeyGenerator keyGenerator = null;  

  26. try {  

  27.            keyGenerator = KeyGenerator.getInstance(algorithm);  

  28.        } catch (NoSuchAlgorithmException e) {  

  29. thrownew RuntimeException(e.getMessage());  

  30.        }  

  31. //产生密钥  

  32.        SecretKey secretKey = keyGenerator.generateKey();  

  33. //获得密钥  

  34. return secretKey.getEncoded();  

  35.    }  

  36. /**

  37.     * 获取 HmaMD5的密钥

  38.     *  

  39.     * @return  HmaMD5的密钥

  40.     * @throws RuntimeException

  41.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  42.     */

  43. publicstaticbyte[] getHmaMD5key(){  

  44. return getHmacKey("HmacMD5");  

  45.    }  

  46. /**

  47.     * 获取 HmaSHA的密钥

  48.     *  

  49.     * @return  HmaSHA的密钥

  50.     * @throws RuntimeException

  51.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  52.     */

  53. publicstaticbyte[] getHmaSHAkey(){  

  54. return getHmacKey("HmacSHA1");  

  55.    }  

  56. /**

  57.     * 获取 HmaSHA256的密钥

  58.     *  

  59.     * @return  HmaSHA256的密钥

  60.     * @throws RuntimeException

  61.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  62.     */

  63. publicstaticbyte[] getHmaSHA256key(){  

  64. return getHmacKey("HmacSHA256");  

  65.    }  

  66. /**

  67.     * 获取 HmaSHA384的密钥

  68.     *  

  69.     * @return  HmaSHA384的密钥

  70.     * @throws RuntimeException

  71.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  72.     */

  73. publicstaticbyte[] getHmaSHA384key(){  

  74. return getHmacKey("HmacSHA384");  

  75.    }  

  76. /**

  77.     * 获取 HmaSHA512的密钥

  78.     *  

  79.     * @return  HmaSHA384的密钥

  80.     * @throws RuntimeException

  81.     *             当 {@link java.security.NoSuchAlgorithmException} 发生时

  82.     */

  83. publicstaticbyte[] getHmaSHA512key(){  

  84. return getHmacKey("HmacSHA512");  

  85.    }  

  86. /**

  87.     * 转换密钥

  88.     *  

  89.     * @param key   二进制密钥

  90.     * @param algorithm 密钥算法

  91.     * @return 密钥

  92.     */

  93. privatestatic Key toKey(byte[] key,String algorithm){  

  94. //生成密钥  

  95. returnnew SecretKeySpec(key, algorithm);  

  96.    }  

  97. /**

  98.     * 使用HmacMD5消息摘要算法计算消息摘要

  99.     *  

  100.     * @param data 做消息摘要的数据

  101.     * @param key 密钥

  102.     * @return 消息摘要(长度为16的字节数组)

  103.     */

  104. publicstaticbyte[] encodeHmacMD5(byte[] data, Key key){  

  105.        Mac mac = null;  

  106. try {  

  107.            mac = Mac.getInstance("HmacMD5");  

  108.            mac.init(key);  

  109.        } catch (NoSuchAlgorithmException e) {  

  110.            e.printStackTrace();  

  111. returnnewbyte[0];  

  112.        }catch (InvalidKeyException e) {  

  113.            e.printStackTrace();  

  114. returnnewbyte[0];  

  115.        }  

  116. return mac.doFinal(data);  

  117.    }  

  118. /**

  119.     * 使用HmacMD5消息摘要算法计算消息摘要

  120.     *  

  121.     * @param data 做消息摘要的数据

  122.     * @param key 密钥

  123.     * @return 消息摘要(长度为16的字节数组)

  124.     */

  125. publicstaticbyte[] encodeHmacMD5(byte[] data, byte[] key){  

  126.        Key k = toKey(key, "HmacMD5");  

  127. return encodeHmacMD5(data, k);  

  128.    }  

  129. /**

  130.     * 使用HmacSHA消息摘要算法计算消息摘要

  131.     *  

  132.     * @param data 做消息摘要的数据

  133.     * @param key 密钥

  134.     * @return 消息摘要(长度为16的字节数组)

  135.     */

  136. publicstaticbyte[] encodeHmacSHA(byte[] data, Key key){  

  137.        Mac mac = null;  

  138. try {  

  139.            mac = Mac.getInstance("HmacSHA1");  

  140.            mac.init(key);  

  141.        } catch (NoSuchAlgorithmException e) {  

  142.            e.printStackTrace();  

  143. returnnewbyte[0];  

  144.        }catch (InvalidKeyException e) {  

  145.            e.printStackTrace();  

  146. returnnewbyte[0];  

  147.        }  

  148. return mac.doFinal(data);  

  149.    }  

  150. /**

  151.     * 使用HmacSHA消息摘要算法计算消息摘要

  152.     *  

  153.     * @param data 做消息摘要的数据

  154.     * @param key 密钥

  155.     * @return 消息摘要(长度为16的字节数组)

  156.     */

  157. publicstaticbyte[] encodeHmacSHA(byte[] data, byte[] key){  

  158.        Key k = toKey(key, "HmacSHA1");  

  159. return encodeHmacSHA(data, k);  

  160.    }  

  161. /**

  162.     * 使用HmacSHA256消息摘要算法计算消息摘要

  163.     *  

  164.     * @param data 做消息摘要的数据

  165.     * @param key 密钥

  166.     * @return 消息摘要(长度为16的字节数组)

  167.     */

  168. publicstaticbyte[] encodeHmacSHA256(byte[] data, Key key){  

  169.        Mac mac = null;  

  170. try {  

  171.            mac = Mac.getInstance("HmacSHA256");  

  172.            mac.init(key);  

  173.        } catch (NoSuchAlgorithmException e) {  

  174.            e.printStackTrace();  

  175. returnnewbyte[0];  

  176.        }catch (InvalidKeyException e) {  

  177.            e.printStackTrace();  

  178. returnnewbyte[0];  

  179.        }  

  180. return mac.doFinal(data);  

  181.    }  

  182. /**

  183.     * 使用HmacSHA256消息摘要算法计算消息摘要

  184.     *  

  185.     * @param data 做消息摘要的数据

  186.     * @param key 密钥

  187.     * @return 消息摘要(长度为16的字节数组)

  188.     */

  189. publicstaticbyte[] encodeHmacSHA256(byte[] data, byte[] key){  

  190.        Key k = toKey(key, "HmacSHA256");  

  191. return encodeHmacSHA256(data, k);  

  192.    }  

  193. /**

  194.     * 使用HmacSHA384消息摘要算法计算消息摘要

  195.     *  

  196.     * @param data 做消息摘要的数据

  197.     * @param key 密钥

  198.     * @return 消息摘要(长度为16的字节数组)

  199.     */

  200. publicstaticbyte[] encodeHmacSHA384(byte[] data, Key key){  

  201.        Mac mac = null;  

  202. try {  

  203.            mac = Mac.getInstance("HmacSHA384");  

  204.            mac.init(key);  

  205.        } catch (NoSuchAlgorithmException e) {  

  206.            e.printStackTrace();  

  207. returnnewbyte[0];  

  208.        }catch (InvalidKeyException e) {  

  209.            e.printStackTrace();  

  210. returnnewbyte[0];  

  211.        }  

  212. return mac.doFinal(data);  

  213.    }  

  214. /**

  215.     * 使用HmacSHA384消息摘要算法计算消息摘要

  216.     *  

  217.     * @param data 做消息摘要的数据

  218.     * @param key 密钥

  219.     * @return 消息摘要(长度为16的字节数组)

  220.     */

  221. publicstaticbyte[] encodeHmacSHA384(byte[] data, byte[] key){  

  222.        Key k = toKey(key, "HmacSHA384");  

  223. return encodeHmacSHA384(data, k);  

  224.    }  

  225. /**

  226.     * 使用HmacSHA512消息摘要算法计算消息摘要

  227.     *  

  228.     * @param data 做消息摘要的数据

  229.     * @param key 密钥

  230.     * @return 消息摘要(长度为16的字节数组)

  231.     */

  232. publicstaticbyte[] encodeHmacSHA512(byte[] data, Key key){  

  233.        Mac mac = null;  

  234. try {  

  235.            mac = Mac.getInstance("HmacSHA512");  

  236.            mac.init(key);  

  237.        } catch (NoSuchAlgorithmException e) {  

  238.            e.printStackTrace();  

  239. returnnewbyte[0];  

  240.        }catch (InvalidKeyException e) {  

  241.            e.printStackTrace();  

  242. returnnewbyte[0];  

  243.        }  

  244. return mac.doFinal(data);  

  245.    }  

  246. /**

  247.     * 使用HmacSHA512消息摘要算法计算消息摘要

  248.     *  

  249.     * @param data 做消息摘要的数据

  250.     * @param key 密钥

  251.     * @return 消息摘要(长度为16的字节数组)

  252.     */

  253. publicstaticbyte[] encodeHmacSHA512(byte[] data, byte[] key){  

  254.        Key k = toKey(key, "HmacSHA512");  

  255. return encodeHmacSHA512(data, k);  

  256.    }  

  257. privatestatic String  showByteArray(byte[] data){  

  258. if(null == data){  

  259. returnnull;  

  260.        }  

  261.        StringBuilder sb = new StringBuilder("{");  

  262. for(byte b:data){  

  263.            sb.append(b).append(",");  

  264.        }  

  265.        sb.deleteCharAt(sb.length()-1);  

  266.        sb.append("}");  

  267. return sb.toString();  

  268.    }  

  269. publicstaticvoid main(String[] args) {  

  270. //      byte[] key = getHmaMD5key();  

  271. //      byte[] key = getHmaSHAkey();  

  272. //      byte[] key = getHmaSHA256key();  

  273. //      byte[] key = getHmaSHA384key();  

  274. byte[] key = getHmaSHA512key();  

  275.        System.out.println("加密密钥: byte[]:"+showByteArray(key).length());  

  276.        String data = "Mac数据";  

  277.        System.out.println("加密前数据: string:"+data);  

  278.        System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));  

  279.        System.out.println();  

  280. //      byte[] encodeData = encodeHmacMD5(data.getBytes(), key);  

  281. //      byte[] encodeData = encodeHmacSHA(data.getBytes(), key);  

  282. //      byte[] encodeData = encodeHmacSHA256(data.getBytes(), key);  

  283. //      byte[] encodeData = encodeHmacSHA384(data.getBytes(), key);  

  284. byte[] encodeData = encodeHmacSHA512(data.getBytes(), key);  

  285.        System.out.println("加密后数据: byte[]:"+showByteArray(encodeData).length());  

  286.        System.out.println("加密后数据: byte[]:"+encodeData.length);  

  287.        System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encodeData));  

  288.        System.out.println();  

  289.    }  

  290. }