[关闭]
@changedi 2016-09-02T01:31:21.000000Z 字数 7014 阅读 2282

Java安全——消息摘要

Java 安全



概念

消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。 消息摘要采用单向Hash 函数将需加密的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。 <<百度百科>>

消息摘要其实是我们日常开发中经常遇到的,比如MD5算法就是一种摘要。它是Java安全提供者体系中最简单的标准引擎。本文不会讨论算法本身,只关注Java语言体系中的实现和使用方法。具体算法原理,后续撰文学习并补充。

使用

消息摘要通过MessageDigest类实现。消息摘要通过getInstance()方法获取算法实例。通过update()方法为消息摘要增加内容字节。根据digest()方法利用累计的内容字节计算最后的摘要。

下面的test列出了一些细节:

  1. import java.io.UnsupportedEncodingException;
  2. import java.security.MessageDigest;
  3. import java.security.NoSuchAlgorithmException;
  4. import java.util.Base64;
  5. import org.apache.commons.codec.binary.Hex;
  6. public class MessageDigestTest {
  7. private static String TEST_DATA = "i am a test";
  8. public static void main(String[] args)
  9. throws NoSuchAlgorithmException, UnsupportedEncodingException {
  10. MessageDigest md = MessageDigest.getInstance("SHA");
  11. print(md);
  12. md = MessageDigest.getInstance("MD5");
  13. print(md);
  14. md = MessageDigest.getInstance("MD2");
  15. print(md);
  16. md = MessageDigest.getInstance("SHA-256");
  17. print(md);
  18. md = MessageDigest.getInstance("SHA-384");
  19. print(md);
  20. md = MessageDigest.getInstance("SHA-224");
  21. print(md);
  22. md = MessageDigest.getInstance("SHA-512");
  23. print(md);
  24. }
  25. private static void print(MessageDigest md) throws UnsupportedEncodingException {
  26. System.out.println("Algorithm:\t" + md.getAlgorithm());
  27. System.out.println("\tProvider:\t" + md.getProvider());
  28. long start = System.nanoTime();
  29. md.update(TEST_DATA.getBytes("UTF-8"));
  30. byte[] digest = md.digest();
  31. long time = System.nanoTime() - start;
  32. System.out.println("\tTime cost:\t" + time + "ns");
  33. System.out.println("\tByte length:\t" + digest.length);
  34. String digestBase64Str = Base64.getEncoder().encodeToString(digest);
  35. System.out.println("\tBase64:\t" + digestBase64Str + "\tlen:\t" + digestBase64Str.length());
  36. String digestHexStr = Hex.encodeHexString(digest);
  37. System.out.println("\tHex:\t" + digestHexStr + "\tlen:\t" + digestHexStr.length());
  38. }
  39. }

输出结果如下:

  1. Algorithm: SHA
  2. Provider: SUN version 1.8
  3. Time cost: 432582ns
  4. Byte length: 20
  5. Base64: Bj5BsD+J+PLpYZYVDR+14WwSKlg= len: 28
  6. Hex: 063e41b03f89f8f2e96196150d1fb5e16c122a58 len: 40
  7. Algorithm: MD5
  8. Provider: SUN version 1.8
  9. Time cost: 46030ns
  10. Byte length: 16
  11. Base64: dCVplUXLIKBlw/aWvoOCyA== len: 24
  12. Hex: 7425699545cb20a065c3f696be8382c8 len: 32
  13. Algorithm: MD2
  14. Provider: SUN version 1.8
  15. Time cost: 80611ns
  16. Byte length: 16
  17. Base64: v4z32/PgSXZCrWvnOcRiaQ== len: 24
  18. Hex: bf8cf7dbf3e0497642ad6be739c46269 len: 32
  19. Algorithm: SHA-256
  20. Provider: SUN version 1.8
  21. Time cost: 205859ns
  22. Byte length: 32
  23. Base64: lRctjSY3GOo6erswsyheP21CNtAAGxnsUHVF17u7RYg= len: 44
  24. Hex: 95172d8d263718ea3a7abb30b3285e3f6d4236d0001b19ec507545d7bbbb4588 len: 64
  25. Algorithm: SHA-384
  26. Provider: SUN version 1.8
  27. Time cost: 258382ns
  28. Byte length: 48
  29. Base64: /B642f1Y+PPKgeIJHFpbEDLJwX2nqWaMaC8nVQuboRWN5MZeKpGaLiySWUEr4xB9 len: 64
  30. Hex: fc1eb8d9fd58f8f3ca81e2091c5a5b1032c9c17da7a9668c682f27550b9ba1158de4c65e2a919a2e2c9259412be3107d len: 96
  31. Algorithm: SHA-224
  32. Provider: SUN version 1.8
  33. Time cost: 76539ns
  34. Byte length: 28
  35. Base64: 6m2pv1G0lnWlKO4ahn7iJAQF8XMo5cHR3LBO3w== len: 40
  36. Hex: ea6da9bf51b49675a528ee1a867ee2240405f17328e5c1d1dcb04edf len: 56
  37. Algorithm: SHA-512
  38. Provider: SUN version 1.8
  39. Time cost: 143649ns
  40. Byte length: 64
  41. Base64: Vv6LL9QqfeCq1ClbN8JdMTcU1PzUbsRQKgmc7vVDbcHTB6i/SryXIjWcRcrfYa6n2QxstmSwUY9AME3pTmykNw== len: 88
  42. Hex: 56fe8b2fd42a7de0aad4295b37c25d313714d4fcd46ec4502a099ceef5436dc1d307a8bf4abc9722359c45cadf61aea7d90c6cb664b0518f40304de94e6ca437 len: 128

消息摘要实现是通过Java自己Sun的实现来做的。我们常见的是MD5和SHA算法。

安全消息摘要

考虑到消息摘要的不安全性——拿到原文并知道算法,就可以得到正确的消息摘要。人们又加入了密钥元素,得到了安全消息摘要——MAC(Message Authentication Code)。MAC的特点是仅通过原文是无法计算出安全消息摘要的。还需要一个双方都知道的消息密钥。如果有人修改了消息本体,又修改了消息摘要,但是因为没有使用密钥,那么将被发现破坏了数据。计算MAC的方法有很多,但是核心Java API没有相关实现。Java的实现主要是通过JCE提供者来实现的。Mac类对应消息摘要的MessageDigest类。计算消息摘要时需要一个密钥。密钥的管理是另一个话题了。这里主要讲MAC的算法,JCE实现主要基于HmacSHA1和HmacMD5。具体provider提供了哪些MAC相关的算法,它们比较如何,见下面的代码:

  1. package com.taobao.cd.security;
  2. import java.security.InvalidKeyException;
  3. import java.security.NoSuchAlgorithmException;
  4. import java.util.Base64;
  5. import javax.crypto.KeyGenerator;
  6. import javax.crypto.Mac;
  7. import javax.crypto.SecretKey;
  8. import org.apache.commons.codec.binary.Hex;
  9. public class MacTest {
  10. public static String TEST_DATA = "I am test";
  11. public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
  12. // TODO Auto-generated method stub
  13. Mac mac = Mac.getInstance("HmacSHA1");
  14. print(mac);
  15. mac = Mac.getInstance("HmacMD5");
  16. print(mac);
  17. mac = Mac.getInstance("SslMacMD5");
  18. print(mac);
  19. mac = Mac.getInstance("HmacSHA384");
  20. print(mac);
  21. mac = Mac.getInstance("HmacSHA256");
  22. print(mac);
  23. mac = Mac.getInstance("HmacSHA224");
  24. print(mac);
  25. mac = Mac.getInstance("SslMacSHA1");
  26. print(mac);
  27. mac = Mac.getInstance("HmacSHA512");
  28. print(mac);
  29. }
  30. private static void print(Mac mac) throws NoSuchAlgorithmException, InvalidKeyException {
  31. System.out.println("Algorithm:\t" + mac.getAlgorithm());
  32. System.out.println("\tProvider:\t" + mac.getProvider());
  33. KeyGenerator kg = KeyGenerator.getInstance("DES");
  34. SecretKey key = kg.generateKey();
  35. long start = System.nanoTime();
  36. mac.init(key);
  37. mac.update(TEST_DATA.getBytes());
  38. byte[] digest = mac.doFinal();
  39. long time = System.nanoTime() - start;
  40. System.out.println("\tTime cost:\t" + time + "ns");
  41. System.out.println("\tByte length:\t" + digest.length);
  42. String digestBase64Str = Base64.getEncoder().encodeToString(digest);
  43. System.out.println("\tBase64:\t" + digestBase64Str + "\tlen:\t" + digestBase64Str.length());
  44. String digestHexStr = Hex.encodeHexString(digest);
  45. System.out.println("\tHex:\t" + digestHexStr + "\tlen:\t" + digestHexStr.length());
  46. }
  47. }

输出如下:

  1. Algorithm: HmacSHA1
  2. Provider: SunJCE version 1.8
  3. Time cost: 259396ns
  4. Byte length: 20
  5. Base64: SVaesT3JpL9Emz5O40aZhpUrX5s= len: 28
  6. Hex: 49569eb13dc9a4bf449b3e4ee3469986952b5f9b len: 40
  7. Algorithm: HmacMD5
  8. Provider: SunJCE version 1.8
  9. Time cost: 136070ns
  10. Byte length: 16
  11. Base64: hBDkDPJ1CpyYqvFN48chqQ== len: 24
  12. Hex: 8410e40cf2750a9c98aaf14de3c721a9 len: 32
  13. Algorithm: SslMacMD5
  14. Provider: SunJCE version 1.8
  15. Time cost: 174089ns
  16. Byte length: 16
  17. Base64: YiEubyE7y+M4JesHQOAV7A== len: 24
  18. Hex: 62212e6f213bcbe33825eb0740e015ec len: 32
  19. Algorithm: HmacSHA384
  20. Provider: SunJCE version 1.8
  21. Time cost: 648249ns
  22. Byte length: 48
  23. Base64: GLic/lwKBA1DdQVbNF5y7L/H8o+0gcO1n02JcdUJMnE9MRwyfHWamEsAJL3ycfFy len: 64
  24. Hex: 18b89cfe5c0a040d4375055b345e72ecbfc7f28fb481c3b59f4d8971d50932713d311c327c759a984b0024bdf271f172 len: 96
  25. Algorithm: HmacSHA256
  26. Provider: SunJCE version 1.8
  27. Time cost: 26007ns
  28. Byte length: 32
  29. Base64: 7LGdb6W8WPYfOXx0WQQ8f35zSGCxs/6op6eOqStuGxA= len: 44
  30. Hex: ecb19d6fa5bc58f61f397c7459043c7f7e734860b1b3fea8a7a78ea92b6e1b10 len: 64
  31. Algorithm: HmacSHA224
  32. Provider: SunJCE version 1.8
  33. Time cost: 125344ns
  34. Byte length: 28
  35. Base64: adoBxnZuCle/ip4FyfCgiQUCmlaN1+RDch9Q9g== len: 40
  36. Hex: 69da01c6766e0a57bf8a9e05c9f0a08905029a568dd7e443721f50f6 len: 56
  37. Algorithm: SslMacSHA1
  38. Provider: SunJCE version 1.8
  39. Time cost: 50672ns
  40. Byte length: 20
  41. Base64: RxCsQguxNXgtqcobgqWdvJeYTKo= len: 28
  42. Hex: 4710ac420bb135782da9ca1b82a59dbc97984caa len: 40
  43. Algorithm: HmacSHA512
  44. Provider: SunJCE version 1.8
  45. Time cost: 365908ns
  46. Byte length: 64
  47. Base64: /Vf5JsSle43/t4aUMkDfdDeUFg3CA0OQAt5izo0bgoUmaVrVOv3tjTLwmrrL/3kACVn38aIDSAIlz8725gl6lA== len: 88
  48. Hex: fd57f926c4a57b8dffb786943240df743794160dc203439002de62ce8d1b828526695ad53afded8d32f09abacbff79000959f7f1a203480225cfcef6e6097a94 len: 128

这里使用的key是通过KeyGenerator生成的。在实际应用中,应该有一方来生成并导出到可管理的KeyStore,使用方载入Keystore再进行摘要生成和校验。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注