JAVA加密解密之消息摘要算法(MessageDigest)

x33g5p2x  于2021-12-25 转载在 其他  
字(4.4k)|赞(0)|评价(0)|浏览(479)

消息摘要算法简介

消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在密钥的管理与分发问题,适合于分布式网络上使用。由于其加密计算的工作量相当可观,所以以前的这种算法通常只用于数据量有限的情况下的加密,例如计算机的口令就是用不可逆加密算法加密的。近年来,随着计算机性能的飞速改善,加密速度不再成为限制这种加密技术发展的桎梏,因而消息摘要算法应用的领域不断增加。

消息摘要算法特点

消息摘要是把任意长度的输入柔和而产生长度固定的伪随机输入的算法。消息摘要的主要特点有:

  1. 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出,SHA-1的变体可以产生192比特位和256比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
  2. 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。但是,一个摘要并不是真正随机的,因为用相同的算法对相同的消息求两次摘要,其结果必然相同;而若是真正随机的,则无论如何都是无法重现的。因此消息摘要是“伪随机的”。
  3. 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。这正是好的消息摘要算法所具有的性质:输入改变了,输出也就改变了;两条相似的消息的摘要确不相近,甚至会大相径庭。
  4. 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。当然,可以采用强力攻击的方法,即尝试每一个可能的信息,计算其摘要,看看是否与已有的摘要相同,如果这样做,最终肯定会恢复出摘要的消息。但实际上,要得到的信息可能是无穷个消息之一,所以这种强力攻击几乎是无效的。
  5. 好的摘要算法,没有人能从中找到“碰撞”,虽然“碰撞”是肯定存在的。即对于给定的一个摘要,不可能找到一条信息使其摘要正好是给定的。或者说,无法找到两条消息,使它们的摘要相同。

消息摘要算法实现

在进行完消息摘要运算之后,我们获得的结果为字节数组,通常我们会将其转换成十六进制的字符串,所以我们首先需要编写一个工具类来完成数据的转换工作,避免重复编码。

package com.jianggujin.codec;

public class HQHex {

   private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
         'E', 'F' };

   public static byte[] decodeHex(final char[] data)
   {

      final int len = data.length;

      if ((len & 0x01) != 0)
      {
         throw new IllegalArgumentException("Odd number of characters.");
      }

      final byte[] out = new byte[len >> 1];

      // two characters form the hex value.
      for (int i = 0, j = 0; j < len; i++)
      {
         int f = toDigit(data[j], j) << 4;
         j++;
         f = f | toDigit(data[j], j);
         j++;
         out[i] = (byte) (f & 0xFF);
      }

      return out;
   }

   public static char[] encodeHex(final byte[] data)
   {
      return encodeHex(data, DIGITS_UPPER);
   }

   protected static char[] encodeHex(final byte[] data, final char[] toDigits)
   {
      final int l = data.length;
      final char[] out = new char[l << 1];
      // two characters form the hex value.
      for (int i = 0, j = 0; i < l; i++)
      {
         out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
         out[j++] = toDigits[0x0F & data[i]];
      }
      return out;
   }

   public static String encodeHexString(final byte[] data)
   {
      return new String(encodeHex(data));
   }

   protected static int toDigit(final char ch, final int index)
   {
      final int digit = Character.digit(ch, 16);
      if (digit == -1)
      {
         throw new IllegalArgumentException("Illegal hexadecimal character " + ch + " at index " + index);
      }
      return digit;
   }
}

在Java中支持的消息摘要算法有:MD2、MD5、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512。我们可以通过MessageDigest获得相关算法的实现。

package com.jianggujin.codec;

import java.security.MessageDigest;

/** * 摘要运算 * * @author jianggujin * */
public class HQMessageDigest {
   private static HQMessageDigest messageDigest = new HQMessageDigest();

   public static HQMessageDigest getInstance()
   {
      return messageDigest;
   }

   private HQMessageDigest()
   {
   }

   /** * 摘要算法 * * @author jianggujin * */
   public static enum HQMessageDigestAlgorithm
   {
      MD2("MD2"), MD5("MD5"), SHA_1("SHA-1"), SHA_224("SHA-224"), SHA_256("SHA-256"), SHA_384("SHA-384"), SHA_512(
            "SHA-512");
      private String name;

      private HQMessageDigestAlgorithm(String name)
      {
         this.name = name;
      }

      public String getName()
      {
         return this.name;
      }
   }

   private MessageDigest getMessageDigest(String algorithm) throws Exception
   {
      return MessageDigest.getInstance(algorithm);
   }

   /** * 加密 * * @param algorithm * @param data * @return */
   public byte[] encrypt(HQMessageDigestAlgorithm algorithm, byte[] data) throws Exception
   {
      return encrypt(algorithm.getName(), data);
   }

   /** * 加密 * * @param algorithm * @param data * @return */
   public byte[] encrypt(String algorithm, byte[] data) throws Exception
   {
      return getMessageDigest(algorithm).digest(data);
   }
}

编写测试代码:

import org.junit.Test;

import com.jianggujin.codec.HQHex;
import com.jianggujin.codec.HQMessageDigest;
import com.jianggujin.codec.HQMessageDigest.HQMessageDigestAlgorithm;

public class MessageDigest {
   HQMessageDigest digest = HQMessageDigest.getInstance();

   @Test
   public void encode() throws Exception
   {
      byte[] data = "jianggujin".getBytes();
      HQMessageDigestAlgorithm[] algorithms = HQMessageDigestAlgorithm.values();
      for (HQMessageDigestAlgorithm algorithm : algorithms)
      {
         System.err.println(algorithm + ":" + HQHex.encodeHexString(digest.encrypt(algorithm, data)));
      }
   }
}

运行结果如下:
MD2:67A38A872221B36D77134F51555A7835
MD5:ACAB4EFDFD3B8EFCDEC37FE160D7BE0E
SHA_1:26635165490065775F7EDEE885392424852DA15A
SHA_224:C7EFCE247D44D13E90330B1689F0FA3D513D5EFBFA83BC3B32D70FB0
SHA_256:E99631966983730ACF4C1FA45669227980C19EF1F7FBEA8FAB2DC897B881CD30
SHA_384:47DED0D29656EAA7443A2BA00C3C13008A56C48EC3F2E5E84A6FECCF8B6F570C1A1B953C93C3341AB0AB0252D388087B
SHA_512:6A677109E89384062E6078767417ED3176128451ECB91FAE59BB3F407A2752579E6C99DE14AF00C7D8ABACC78395CD587BFD945B9045F8CA227BB2FC8B140CDA

相关文章