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

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. importjava.security.MessageDigest;
  2. importjava.security.NoSuchAlgorithmException;
  3. /**
  4. *referenceapachecommons<a
  5. *href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>
  6. *
  7. *supportMD2/MD5/SHA/SHA256/SHA384/SHA512
  8. *@authorAub
  9. *
  10. */
  11. publicclassDigestUtils{
  12. /**
  13. *根据给定摘要算法创建一个消息摘要实例
  14. *
  15. *@paramalgorithm
  16. *摘要算法名
  17. *@return消息摘要实例
  18. *@seeMessageDigest#getInstance(String)
  19. *@throwsRuntimeException
  20. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  21. */
  22. staticMessageDigestgetDigest(Stringalgorithm){
  23. try{
  24. returnMessageDigest.getInstance(algorithm);
  25. }catch(NoSuchAlgorithmExceptione){
  26. thrownewRuntimeException(e.getMessage());
  27. }
  28. }
  29. /**
  30. *获取MD5消息摘要实例
  31. *
  32. *@returnMD5消息摘要实例
  33. *@throwsRuntimeException
  34. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  35. */
  36. privatestaticMessageDigestgetMd5Digest(){
  37. returngetDigest("MD5");
  38. }
  39. /**
  40. *获取SHA-1消息摘要实例
  41. *
  42. *@returnSHA-1消息摘要实例
  43. *@throwsRuntimeException
  44. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  45. */
  46. privatestaticMessageDigestgetShaDigest(){
  47. returngetDigest("SHA");
  48. }
  49. /**
  50. *获取SHA-256消息摘要实例
  51. *
  52. *@returnSHA-256消息摘要实例
  53. *@throwsRuntimeException
  54. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  55. */
  56. privatestaticMessageDigestgetSha256Digest(){
  57. returngetDigest("SHA-256");
  58. }
  59. /**
  60. *获取SHA-384消息摘要实例
  61. *
  62. *@returnSHA-384消息摘要实例
  63. *@throwsRuntimeException
  64. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  65. */
  66. privatestaticMessageDigestgetSha384Digest(){
  67. returngetDigest("SHA-384");
  68. }
  69. /**
  70. *获取SHA-512消息摘要实例
  71. *
  72. *@returnSHA-512消息摘要实例
  73. *@throwsRuntimeException
  74. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  75. */
  76. privatestaticMessageDigestgetSha512Digest(){
  77. returngetDigest("SHA-512");
  78. }
  79. /**
  80. *使用MD5消息摘要算法计算消息摘要
  81. *
  82. *@paramdata
  83. *做消息摘要的数据
  84. *@return消息摘要(长度为16的字节数组)
  85. */
  86. publicstaticbyte[]encodeMD5(byte[]data){
  87. returngetMd5Digest().digest(data);
  88. }
  89. /**
  90. *使用MD5消息摘要算法计算消息摘要
  91. *
  92. *@paramdata
  93. *做消息摘要的数据
  94. *@return消息摘要(长度为32的十六进制字符串)
  95. */
  96. publicstaticStringencodeMD5Hex(byte[]data){
  97. returnHex.encodeHexStr(encodeMD5(data));
  98. }
  99. /**
  100. *使用SHA-1消息摘要算法计算消息摘要
  101. *
  102. *@paramdata
  103. *做消息摘要的数据
  104. *@returnSHA-1消息摘要(长度为20的字节数组)
  105. */
  106. publicstaticbyte[]encodeSHA(byte[]data){
  107. returngetShaDigest().digest(data);
  108. }
  109. /**
  110. *使用SHA-1消息摘要算法计算消息摘要
  111. *
  112. *@paramdata
  113. *做消息摘要的数据
  114. *@returnSHA-1消息摘要(长度为40的十六进制字符串)
  115. */
  116. publicstaticStringencodeSHAHex(byte[]data){
  117. returnHex.encodeHexStr(getShaDigest().digest(data));
  118. }
  119. /**
  120. *使用SHA-256消息摘要算法计算消息摘要
  121. *
  122. *@paramdata
  123. *做消息摘要的数据
  124. *@returnSHA-256消息摘要(长度为32的字节数组)
  125. */
  126. publicstaticbyte[]encodeSHA256(byte[]data){
  127. returngetSha256Digest().digest(data);
  128. }
  129. /**
  130. *使用SHA-256消息摘要算法计算消息摘要
  131. *
  132. *@paramdata
  133. *做消息摘要的数据
  134. *@returnSHA-256消息摘要(长度为64的十六进制字符串)
  135. */
  136. publicstaticStringencodeSHA256Hex(byte[]data){
  137. returnHex.encodeHexStr(encodeSHA256(data));
  138. }
  139. /**
  140. *使用SHA-384消息摘要算法计算消息摘要
  141. *
  142. *@paramdata
  143. *做消息摘要的数据
  144. *@returnSHA-384消息摘要(长度为43的字节数组)
  145. */
  146. publicstaticbyte[]encodeSHA384(byte[]data){
  147. returngetSha384Digest().digest(data);
  148. }
  149. /**
  150. *使用SHA-384消息摘要算法计算消息摘要
  151. *
  152. *@paramdata
  153. *做消息摘要的数据
  154. *@returnSHA-384消息摘要(长度为86的十六进制字符串)
  155. */
  156. publicstaticStringencodeSHA384Hex(byte[]data){
  157. returnHex.encodeHexStr(encodeSHA384(data));
  158. }
  159. /**
  160. *使用SHA-512消息摘要算法计算消息摘要
  161. *
  162. *@paramdata
  163. *做消息摘要的数据
  164. *@returnSHA-512消息摘要(长度为64的字节数组)
  165. */
  166. publicstaticbyte[]encodeSHA512(byte[]data){
  167. returngetSha512Digest().digest(data);
  168. }
  169. /**
  170. *使用SHA-512消息摘要算法计算消息摘要
  171. *
  172. *@paramdata
  173. *做消息摘要的数据
  174. *@returnSHA-512消息摘要(长度为128的十六进制字符串)
  175. */
  176. publicstaticStringencodeSHA512Hex(byte[]data){
  177. returnHex.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. importjava.security.InvalidKeyException;
  2. importjava.security.Key;
  3. importjava.security.NoSuchAlgorithmException;
  4. importjavax.crypto.KeyGenerator;
  5. importjavax.crypto.Mac;
  6. importjavax.crypto.SecretKey;
  7. importjavax.crypto.spec.SecretKeySpec;
  8. /**
  9. *Hmac<br/>
  10. *algorithmHmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512
  11. *@authorAub
  12. */
  13. publicclassHmac{
  14. /**
  15. *根据给定密钥生成算法创建密钥
  16. *
  17. *@paramalgorithm
  18. *密钥算法
  19. *@return密钥
  20. *@throwsRuntimeException
  21. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  22. */
  23. privatestaticbyte[]getHmacKey(Stringalgorithm){
  24. //初始化KeyGenerator
  25. KeyGeneratorkeyGenerator=null;
  26. try{
  27. keyGenerator=KeyGenerator.getInstance(algorithm);
  28. }catch(NoSuchAlgorithmExceptione){
  29. thrownewRuntimeException(e.getMessage());
  30. }
  31. //产生密钥
  32. SecretKeysecretKey=keyGenerator.generateKey();
  33. //获得密钥
  34. returnsecretKey.getEncoded();
  35. }
  36. /**
  37. *获取HmaMD5的密钥
  38. *
  39. *@returnHmaMD5的密钥
  40. *@throwsRuntimeException
  41. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  42. */
  43. publicstaticbyte[]getHmaMD5key(){
  44. returngetHmacKey("HmacMD5");
  45. }
  46. /**
  47. *获取HmaSHA的密钥
  48. *
  49. *@returnHmaSHA的密钥
  50. *@throwsRuntimeException
  51. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  52. */
  53. publicstaticbyte[]getHmaSHAkey(){
  54. returngetHmacKey("HmacSHA1");
  55. }
  56. /**
  57. *获取HmaSHA256的密钥
  58. *
  59. *@returnHmaSHA256的密钥
  60. *@throwsRuntimeException
  61. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  62. */
  63. publicstaticbyte[]getHmaSHA256key(){
  64. returngetHmacKey("HmacSHA256");
  65. }
  66. /**
  67. *获取HmaSHA384的密钥
  68. *
  69. *@returnHmaSHA384的密钥
  70. *@throwsRuntimeException
  71. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  72. */
  73. publicstaticbyte[]getHmaSHA384key(){
  74. returngetHmacKey("HmacSHA384");
  75. }
  76. /**
  77. *获取HmaSHA512的密钥
  78. *
  79. *@returnHmaSHA384的密钥
  80. *@throwsRuntimeException
  81. *当{@linkjava.security.NoSuchAlgorithmException}发生时
  82. */
  83. publicstaticbyte[]getHmaSHA512key(){
  84. returngetHmacKey("HmacSHA512");
  85. }
  86. /**
  87. *转换密钥
  88. *
  89. *@paramkey二进制密钥
  90. *@paramalgorithm密钥算法
  91. *@return密钥
  92. */
  93. privatestaticKeytoKey(byte[]key,Stringalgorithm){
  94. //生成密钥
  95. returnnewSecretKeySpec(key,algorithm);
  96. }
  97. /**
  98. *使用HmacMD5消息摘要算法计算消息摘要
  99. *
  100. *@paramdata做消息摘要的数据
  101. *@paramkey密钥
  102. *@return消息摘要(长度为16的字节数组)
  103. */
  104. publicstaticbyte[]encodeHmacMD5(byte[]data,Keykey){
  105. Macmac=null;
  106. try{
  107. mac=Mac.getInstance("HmacMD5");
  108. mac.init(key);
  109. }catch(NoSuchAlgorithmExceptione){
  110. e.printStackTrace();
  111. returnnewbyte[0];
  112. }catch(InvalidKeyExceptione){
  113. e.printStackTrace();
  114. returnnewbyte[0];
  115. }
  116. returnmac.doFinal(data);
  117. }
  118. /**
  119. *使用HmacMD5消息摘要算法计算消息摘要
  120. *
  121. *@paramdata做消息摘要的数据
  122. *@paramkey密钥
  123. *@return消息摘要(长度为16的字节数组)
  124. */
  125. publicstaticbyte[]encodeHmacMD5(byte[]data,byte[]key){
  126. Keyk=toKey(key,"HmacMD5");
  127. returnencodeHmacMD5(data,k);
  128. }
  129. /**
  130. *使用HmacSHA消息摘要算法计算消息摘要
  131. *
  132. *@paramdata做消息摘要的数据
  133. *@paramkey密钥
  134. *@return消息摘要(长度为16的字节数组)
  135. */
  136. publicstaticbyte[]encodeHmacSHA(byte[]data,Keykey){
  137. Macmac=null;
  138. try{
  139. mac=Mac.getInstance("HmacSHA1");
  140. mac.init(key);
  141. }catch(NoSuchAlgorithmExceptione){
  142. e.printStackTrace();
  143. returnnewbyte[0];
  144. }catch(InvalidKeyExceptione){
  145. e.printStackTrace();
  146. returnnewbyte[0];
  147. }
  148. returnmac.doFinal(data);
  149. }
  150. /**
  151. *使用HmacSHA消息摘要算法计算消息摘要
  152. *
  153. *@paramdata做消息摘要的数据
  154. *@paramkey密钥
  155. *@return消息摘要(长度为16的字节数组)
  156. */
  157. publicstaticbyte[]encodeHmacSHA(byte[]data,byte[]key){
  158. Keyk=toKey(key,"HmacSHA1");
  159. returnencodeHmacSHA(data,k);
  160. }
  161. /**
  162. *使用HmacSHA256消息摘要算法计算消息摘要
  163. *
  164. *@paramdata做消息摘要的数据
  165. *@paramkey密钥
  166. *@return消息摘要(长度为16的字节数组)
  167. */
  168. publicstaticbyte[]encodeHmacSHA256(byte[]data,Keykey){
  169. Macmac=null;
  170. try{
  171. mac=Mac.getInstance("HmacSHA256");
  172. mac.init(key);
  173. }catch(NoSuchAlgorithmExceptione){
  174. e.printStackTrace();
  175. returnnewbyte[0];
  176. }catch(InvalidKeyExceptione){
  177. e.printStackTrace();
  178. returnnewbyte[0];
  179. }
  180. returnmac.doFinal(data);
  181. }
  182. /**
  183. *使用HmacSHA256消息摘要算法计算消息摘要
  184. *
  185. *@paramdata做消息摘要的数据
  186. *@paramkey密钥
  187. *@return消息摘要(长度为16的字节数组)
  188. */
  189. publicstaticbyte[]encodeHmacSHA256(byte[]data,byte[]key){
  190. Keyk=toKey(key,"HmacSHA256");
  191. returnencodeHmacSHA256(data,k);
  192. }
  193. /**
  194. *使用HmacSHA384消息摘要算法计算消息摘要
  195. *
  196. *@paramdata做消息摘要的数据
  197. *@paramkey密钥
  198. *@return消息摘要(长度为16的字节数组)
  199. */
  200. publicstaticbyte[]encodeHmacSHA384(byte[]data,Keykey){
  201. Macmac=null;
  202. try{
  203. mac=Mac.getInstance("HmacSHA384");
  204. mac.init(key);
  205. }catch(NoSuchAlgorithmExceptione){
  206. e.printStackTrace();
  207. returnnewbyte[0];
  208. }catch(InvalidKeyExceptione){
  209. e.printStackTrace();
  210. returnnewbyte[0];
  211. }
  212. returnmac.doFinal(data);
  213. }
  214. /**
  215. *使用HmacSHA384消息摘要算法计算消息摘要
  216. *
  217. *@paramdata做消息摘要的数据
  218. *@paramkey密钥
  219. *@return消息摘要(长度为16的字节数组)
  220. */
  221. publicstaticbyte[]encodeHmacSHA384(byte[]data,byte[]key){
  222. Keyk=toKey(key,"HmacSHA384");
  223. returnencodeHmacSHA384(data,k);
  224. }
  225. /**
  226. *使用HmacSHA512消息摘要算法计算消息摘要
  227. *
  228. *@paramdata做消息摘要的数据
  229. *@paramkey密钥
  230. *@return消息摘要(长度为16的字节数组)
  231. */
  232. publicstaticbyte[]encodeHmacSHA512(byte[]data,Keykey){
  233. Macmac=null;
  234. try{
  235. mac=Mac.getInstance("HmacSHA512");
  236. mac.init(key);
  237. }catch(NoSuchAlgorithmExceptione){
  238. e.printStackTrace();
  239. returnnewbyte[0];
  240. }catch(InvalidKeyExceptione){
  241. e.printStackTrace();
  242. returnnewbyte[0];
  243. }
  244. returnmac.doFinal(data);
  245. }
  246. /**
  247. *使用HmacSHA512消息摘要算法计算消息摘要
  248. *
  249. *@paramdata做消息摘要的数据
  250. *@paramkey密钥
  251. *@return消息摘要(长度为16的字节数组)
  252. */
  253. publicstaticbyte[]encodeHmacSHA512(byte[]data,byte[]key){
  254. Keyk=toKey(key,"HmacSHA512");
  255. returnencodeHmacSHA512(data,k);
  256. }
  257. privatestaticStringshowByteArray(byte[]data){
  258. if(null==data){
  259. returnnull;
  260. }
  261. StringBuildersb=newStringBuilder("{");
  262. for(byteb:data){
  263. sb.append(b).append(",");
  264. }
  265. sb.deleteCharAt(sb.length()-1);
  266. sb.append("}");
  267. returnsb.toString();
  268. }
  269. publicstaticvoidmain(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. Stringdata="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. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值