定义:

消息摘要算法又称为散列算法,其核心在于散列函数的单向性。即通过散列函数可获得对应的散列值,但不可通过该散列值反推其原始数据信息,这是消息摘要算法的安全性的根本所在。

分类:

消息摘要算法主要分为三大类:MD(Message Digest,消息摘要算法)、SHA(Secure Hash Algorithm,安全散列算法)和MAC(Message Authentication Code,消息认证码算法)

其他:RipeMD系列、Tiger、GOST3411和Whirlpool算法

MD算法系列

原理:

  1. 根据一个随机长度的信息产生一个128位的信息摘要
  2. 将128位的二进制摘要信息换算成十六进制,可以得到一个32位都是十六进制的字符串。

分类:

MD2,MD4,MD5三种,其中java6提供了MD2和MD5的实现,Commons Codec对java6的MD5算法进行了封装(DigestUtils支持更多形式的参数),MD4由Bouncy Castle提供。

MessageDigest代码实例:

//明文信息
byte[] input = "sha".getBytes();
//获取MessageDigest对象,使用MD5算法
MessageDigest messageDegist = MessageDigest.getInstance("md5");
//更新摘要信息
messageDegist.update(input);
//获取消息摘要结果
byte[] output = messageDegist.digest();
//打印出数据
System.out.println(new BigInteger(output));

//打印结果 36899609604734332497826750572321138456

DigestInputStream代码实例

//等待做消息摘要的原始信息
byte[] input = "md5".getBytes();
MessageDigest messageDigest = MessageDigest.getInstance("md5");
DigestInputStream dis = new DigestInputStream(new ByteArrayInputStream(input),messageDigest);
try {
    dis.read(input,0,input.length);
    byte[] disgest = dis.getMessageDigest().digest();
    System.out.println(new BigInteger(disgest));
} catch (Exception e) {
    e.printStackTrace();
}finally {
    try {
        dis.close();
    } catch (IOException e) {
           e.printStackTrace();
    }
}
//打印结果 36899609604734332497826750572321138456

DigestOutputStream代码实例

byte[] bytes = "md2".getBytes();
MessageDigest messageDigest = MessageDigest.getInstance("md2");
try (DigestOutputStream dos = new DigestOutputStream(new ByteArrayOutputStream(),messageDigest)){
    dos.write(bytes,0,bytes.length);
    byte[] output = dos.getMessageDigest().digest();
    System.out.println(new BigInteger(output));
} catch (Exception e) {
    e.printStackTrace();
}
//打印结果 -145043877083066438171874784815250627066

SHA系列

SHA算法是在MD4算法的基础上演进而来的,通过SHA算法同样能够获得一个固定长度的摘要信息。与MD系列不同的是:若输入的消息不同,则与其相对应的摘要信息的差异概率很高。

安全定义:

  1. 由消息摘要反推原输入信息,从计算理论上来说是很困难的。
  2. 想要找到两组不同的消息对应到相同的消息摘要从计算理论上是很困难的。任何对输入消息的变动,都有很高的机率导致其产生迥异的消息摘要。

其实现规则和MD类似,可以参考上面的实规则。

MAC系列

MAC算法结合了MD5和SHA算法的优势,并加入密钥的支持,是一种更为安全的消息摘要算法。因此,我们也常把MAC称为HMAC(keyed-Hash Message Authentication Code)。MD系列的有:HmacMD2、HmacMD4和HmacMD5;SHA系列有:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384和HmacSHA512。

//加密工具类
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;

public class MacCoder {

    /**
     * 初始化HmacMD2的密钥
     * @return 秘密密钥
     * @throws Exception
     */
    public static byte[] initHmacMD2Key() throws Exception {
        return initHmacKey("HmacMD2");
    }

    /**
     * encodeHmacMD2消息摘要
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encodeHmacMD2(byte[] data,byte[] key) throws Exception {
        return encodeHmac(data,key,"HmacMD2");
    }

    /**
     * HmacMD2Hex消息摘要
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static String encodeHmacMD2Hex(byte[] data,byte[] key) throws Exception {
        return encodeHmacHex(data,key,"HmacMD2");
    }

    /**
     * HmacMD4密钥生成
     * @return
     * @throws Exception
     */
   public static byte[] initHmacMD4Key() throws Exception {
        return initHmacKey("HmacMD4");
   }

    /**
     * HmacMD4消息摘要
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
   public static byte[] encodeHmacMD4(byte[] data,byte[] key) throws Exception{
       return encodeHmac(data,key,"HmacMD4");
   }

    /**
     * encodeHmacMD4Hex消息摘要
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
   public static String encodeHmacMD4Hex(byte[] data,byte[] key) throws Exception {
      return encodeHmacHex(data,key,"HmacMD4");
   }

    /**
     * 生成指定的密钥对象
     * @param algorithm
     * @return
     * @throws Exception
     */
   public static byte[] initHmacKey(String algorithm) throws Exception {
       //提供BouncyCastleProvider支持
       Security.addProvider(new BouncyCastleProvider());
       //创建密钥生成对象
       KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
       //生成私密密钥
       SecretKey secretKey = keyGenerator.generateKey();
       //生成密钥
       return secretKey.getEncoded();
   }

    /**
     * 进行指定算法的摘要处理
     * @param data 代加密数据
     * @param key 密钥
     * @param algorithm 方法参数
     * @return
     * @throws Exception
     */
   public static byte[] encodeHmac(byte[] data,byte[] key,String algorithm) throws Exception {
       //添加支持
       Security.addProvider(new BouncyCastleProvider());
       //还原密钥对象
       SecretKey secretKey = new SecretKeySpec(key,algorithm);
       //实例化Mac
       Mac mac = Mac.getInstance(secretKey.getAlgorithm());
       //初始化
       mac.init(secretKey);
       //消息摘要
       return mac.doFinal(data);
   }

    /**
     * 返回十六进制的字符串表示
     * @param data
     * @param key
     * @param algorithm
     * @return
     * @throws Exception
     */
   public static String encodeHmacHex(byte[] data,byte[] key,String algorithm) throws Exception {
       byte[] bytes = encodeHmac(data, key, algorithm);
       return Hex.toHexString(bytes);
   }
}

//加密测试
@Test
public void test(){
    try {
        byte[] key = MacCoder.initHmacMD2Key();
        byte[] data = "到底真的假的".getBytes("utf-8");
        System.out.println("HmacMD2:"+MacCoder.encodeHmacMD2Hex(data,key));
        byte[] key1 = MacCoder.initHmacMD4Key();
        System.out.println("HmacMD4:"+MacCoder.encodeHmacMD4Hex(data,key1));
        byte[] key2 = MacCoder.initHmacKey("HmacSHA224");
        System.out.println("HmacSHA224:"+MacCoder.encodeHmacHex(data,key2,"HmacSHA224"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

//打印结果
HmacMD2:90790be26d3a834f6fb1000ed93ad30e
HmacMD4:79ea3c69b9d8b25398e5f06e0d2d3bc4
HmacSHA224:65ec6091fbb409242ab10440ce00785e957625bd61575af109fa8ac3

其他消息摘要算法

RipeMD、Tiger(最快的Hash算法192位)、WhirlPool(采用了AES加密标准,最安全的摘要算法)、GOST3411(256位)

Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("RipeMD160");
byte[] b = md.digest("开心".getBytes("utf-8"));