数据完整性验证之数字摘要算法

数字摘要算法

  • 1.消息摘要算法概述
  • 2.用户注册及登录模型
  • 3. MD算法家族
    • 3.1 算法实现
    • 3.2 测试代码
  • 4. SHA算法家族
    • 4.1 SHA模型分析
    • 4.2 SHA实现
      • 4.2.1 SHA算法实现
      • 4.2.2 测试代码
  • 5. Commons Codec
  • 6. MAC算法家族
    • 6.1 模型分析
    • 6.2 MAC算法实现
      • 6.2.1 MAC算法代码实现
      • 6.2.2 测试代码

1.消息摘要算法概述

消息摘要算法包含MD、SHA和MAC共3大系列,常用于验证数据的完整性,是数字签名算法的核心算法。数字签名算法常用函数为散列函数,用于数据完整性校验。任何消息经过散列函数处理后,都会获得唯一的散列值。这一过程称为“消息摘要”, 其散列值成为“数字指纹”,自然其算法就是“消息摘要算法”了。如果其数字指纹唯一,就说明其消息是一致的。

消息摘要算法一直是非对称加密算法中一项举足轻重的关键算法。

消息摘要算法主要分为三大类:MD(Message Digest, 消息摘要算法)、SHA(Secure Hash Algorithm,安全散列算法)和MAC(Message Authentication Code,消息认证码算法)。
MD系列算法包括MD2、MD4和MD5共三种算法,SHA算法主要包括其代表算法SHA-1和SHA-1算法变种SHA-2系列算法(包括SHA-224、SHA-256、SHA-384和SHA-512),MAC算法综合了上述两种算法,主要包括HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384和HmacSHA512算法。

后来又衍生出了RipeMD系列(包含RipeMD128、RipeMD160、RipeMD256、RipeMD320)、Tiger、GOST3411和Whirlpool算法。

MD5产生128位二进制摘要信息,换算成32位十六进制字符串

在通用的登录模型中,我们保存在数据库中的密码通常是密文,即通过MD5运算过的值,登录验证时,将密码做MD5运算,然后与数据库保存的值做比较。这里的明文与密文存在对应关系,但仅限于明文到密文的转换,即便是消息摘要算法泄漏也不能反推密码,增强了系统安全性。

为了进一步加强安全性,往往将一些其他的不变信息,如用户名、Email地址串入原始密码中,使得密码破译难度加大。其中,不变信息称为“盐”, 而这种处理方式称为“加盐处理”。实际是对原始信息的一堆混淆。PBE中也采用了中做法。

2.用户注册及登录模型

下图是使用MD注册的流程
数据完整性验证之数字摘要算法_第1张图片
下图是使用MD登录验证的流程
数据完整性验证之数字摘要算法_第2张图片

3. MD算法家族

MD实现细节如下面表格所示

算法 摘要长度 备注
MD2 128 Bouncy Castle
MD5 128 Java6
MD4 128 Bouncy Castle

3.1 算法实现

package com.calvin.android.demo2.secrity;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.security.MessageDigest;
import java.security.Security;

/**
 * Author:cl
 * Email:[email protected]
 * Date:20-10-27
 */
public class MDCoder {

    /**
     * MD2消息摘要
     * @param data 待做摘要处理的数据
     * @return byte[] 消息摘要
     * @throws Exception 异常
     */
    public static byte[] encodeMD2(byte[] data) throws Exception {
        Security.removeProvider("BC");
        Security.addProvider(new BouncyCastleProvider());
        //初始化MessageDigest
        MessageDigest md = MessageDigest.getInstance("MD2");
        //执行消息摘要
        return md.digest(data);
    }

    /**
     * MD5消息摘要
     * @param data 待做摘要处理的数据
     * @return byte[] 消息摘要
     * @throws Exception 异常
     */
    public static byte[] encodeMD5(byte[] data) throws Exception {
        //初始化MessageDigest
        MessageDigest md = MessageDigest.getInstance("MD5");
        //执行消息摘要
        return md.digest(data);
    }

    /**
     * MD4消息摘要
     * @param data 待做摘要处理的数据
     * @return byte[] 消息摘要
     * @throws Exception 异常
     */
    public static byte[] encodeMD4(byte[] data) throws Exception {
        Security.removeProvider("BC");
        Security.addProvider(new BouncyCastleProvider());
        //初始化MessageDigest
        MessageDigest md = MessageDigest.getInstance("MD4");
        //执行消息摘要
        return md.digest(data);
    }

    public static String encodeMD4Hex(byte[] data) throws Exception {
        //执行消息摘要
        byte[] b = encodeMD4(data);
        return new String(Hex.encode(b));
    }
}

3.2 测试代码

 /**
     * 测试MD2
     * @throws Exception
     */
    @Test
    public void testEncodeMD2() throws Exception {
        String str = "MD2消息摘要";
        byte[] data1 = MDCoder.encodeMD2(str.getBytes());
        byte[] data2 = MDCoder.encodeMD2(str.getBytes());
        assertArrayEquals(data1, data2);
    }

    /**
     * 测试MD5
     * @throws Exception
     */
    @Test
    public void testEncodeMD5() throws Exception {
        String str = "MD5消息摘要";
        byte[] data1 = MDCoder.encodeMD5(str.getBytes());
        byte[] data2 = MDCoder.encodeMD5(str.getBytes());
        assertArrayEquals(data1, data2);
    }

    /**
     * 测试MD4
     * @throws Exception
     */
    @Test
    public void testEncodeMD4() throws Exception {
        String str = "MD4消息摘要";
        byte[] data1 = MDCoder.encodeMD4(str.getBytes());
        byte[] data2 = MDCoder.encodeMD4(str.getBytes());
        assertArrayEquals(data1, data2);
    }

4. SHA算法家族

SHA算法基于MD4算法,摘要长度更长,安全性更高,是MD5算法继任者。SHA算法家族目前共有SHA1、SHA-224、SHA-256、SHA384和SHA512五种算法,后四种算法并称SHA-2算法。

4.1 SHA模型分析

下图是基于MD/SHA算法的消息传递模型
数据完整性验证之数字摘要算法_第3张图片

4.2 SHA实现

Java及Bouncy Castle实现细节如下

算法 摘要长度 备注
SHA-1 160 Java 6
SHA-256 256 Java 6
SHA-384 384 Java 6
SHA-512 512 Java 6
SHA-224 224 Bouncy Castle

4.2.1 SHA算法实现

package com.calvin.android.demo2.secrity;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.security.MessageDigest;
import java.security.Security;

/**
 * Author:cl
 * Email:[email protected]
 * Date:20-10-27
 */
public class ShaCoder {

    public static byte[] encodeSHA(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA");
        return md.digest(data);
    }


    public static byte[] encodeSHA256(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        return md.digest(data);
    }

    public static byte[] encodeSHA384(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-384");
        return md.digest(data);
    }

    public static byte[] encodeSHA512(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        return md.digest(data);
    }

    public static byte[] encodeSHA224(byte[] data) throws Exception {
        //加入Bouncy Castle Provider支持
        Security.removeProvider("BC");
        Security.addProvider(new BouncyCastleProvider());
        //初始化MessageDigest
        MessageDigest md = MessageDigest.getInstance("SHA-224");
        //执行消息摘要
        return md.digest(data);
    }

    public static String encodeSHA224Hex(byte[] data) throws Exception {
        //执行消息摘要
        byte[] b = encodeSHA224(data);
        //做十六进制编码处理
        return new String(Hex.encode(b));
    }
}

4.2.2 测试代码

 /**
     * 测试SHA-1
     * @throws Exception
     */
    @Test
    public void testEncodeSHA() throws Exception {
        String str = "SHA1消息摘要";
        //获得摘要信息
        byte[] data1 = ShaCoder.encodeSHA(str.getBytes());
        byte[] data2 = ShaCoder.encodeSHA(str.getBytes());
        //校验
        assertArrayEquals(data1, data2);
    }


    /**
     * 测试SHA-256
     * @throws Exception
     */
    @Test
    public void testEncodeSHA256() throws Exception {
        String str = "SHA256消息摘要";
        //获得摘要信息
        byte[] data1 = ShaCoder.encodeSHA256(str.getBytes());
        byte[] data2 = ShaCoder.encodeSHA256(str.getBytes());
        //校验
        assertArrayEquals(data1, data2);
    }

    /**
     * 测试SHA-384
     * @throws Exception
     */
    @Test
    public void testEncodeSHA384() throws Exception {
        String str = "SHA384消息摘要";
        //获得摘要信息
        byte[] data1 = ShaCoder.encodeSHA384(str.getBytes());
        byte[] data2 = ShaCoder.encodeSHA384(str.getBytes());
        //校验
        assertArrayEquals(data1, data2);
    }

    /**
     * 测试SHA-512
     * @throws Exception
     */
    @Test
    public void testEncodeSHA512() throws Exception {
        String str = "SHA512消息摘要";
        //获得摘要信息
        byte[] data1 = ShaCoder.encodeSHA512(str.getBytes());
        byte[] data2 = ShaCoder.encodeSHA512(str.getBytes());
        //校验
        assertArrayEquals(data1, data2);
    }

    @Test
    public void testEncodeSHA224() throws Exception {
        String str = "SHA224消息摘要";
        //获得摘要信息
        byte[] data1 = ShaCoder.encodeSHA224(str.getBytes());
        byte[] data2 = ShaCoder.encodeSHA224(str.getBytes());
        //校验
        assertArrayEquals(data1, data2);
    }

    @Test
    public void testEncodeSHA224Hex() throws Exception {
        String str = "SHA224消息摘要";
        //获得摘要信息
        String data1 = ShaCoder.encodeSHA224Hex(str.getBytes());
        String data2 = ShaCoder.encodeSHA224Hex(str.getBytes());
        //校验
        assertEquals(data1, data2);
    }

5. Commons Codec

DigestUtils类除了MD5算法外,还支持多种SHA系列算法,Commons Codec与Sun所提供的SHA算法本质毫无差别,关键在于Commons Codec提供了更为方便的实现。

public static byte[] encodeSHA(String data) throws Exception {
        return DigestUtils.sha1(data);
    }

    public static String encodeSHAHex(String data) throws Exception {
        return DigestUtils.sha1Hex(data);
    }

6. MAC算法家族

MAC算法结合了MD5和SHA算法优势,并加入密钥支持,是一种更为安全的消息摘要算法。

MAC(Message Authentication Code, 消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法特性, 并在此基础上加入了密钥。因此,我们也常把MAC称为HMAC(keyed-Hash Message Authentication Code)。
MAC算法主要集合了MD和SHA两大系列消息摘要算法。MD系列算法有HmacMD2、HmacMD4和HmacMD5三种算法; SHA系列算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384和HmacSHA512五种算法。

经过MAC算法的摘要值长度与参与实现的算法摘要值长度相同。

6.1 模型分析

数据完整性验证之数字摘要算法_第4张图片

6.2 MAC算法实现

实现细节如下所示

算法 摘要长度 备注
HmacMD5 128 Java
HmacSHA1 160 Java
HmacSHA256 256 Java
HmacSHA384 384 Java
HmacSHA512 512 Java
HmacMD2 128 Bouncy Castle
HmacMD4 128 Bouncy Castle
HmacSHA224 224 Bouncy Castle

6.2.1 MAC算法代码实现

package com.calvin.android.demo2.secrity;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Author:cl
 * Email:[email protected]
 * Date:20-10-27
 */
public class MACCoder {

    public static byte[] initHmacMD5Key() throws Exception {
        //初始化KeyGenerator
        KeyGenerator kg = KeyGenerator.getInstance("HmacMD5");
        //产生密钥
        SecretKey secretKey = kg.generateKey();
        //获得密钥
        return secretKey.getEncoded();
    }

    public static byte[] encodeHmacMD5(byte[] data, byte[] key) throws Exception{
       //还原密钥
        SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
        //实例化Mac
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        //初始化Mac
        mac.init(secretKey);
        //执行消息摘要
        return mac.doFinal(data);
    }

    /**
     * 初始化 HmacSHA1 密钥
     * @return byte[] 密钥
     * @throws Exception
     */
    public static byte[] initHmacSHAKey() throws Exception {
        //初始化KeyGenerator
        KeyGenerator kg = KeyGenerator.getInstance("HmacSHA1");
        //产生密钥
        SecretKey secretKey = kg.generateKey();
        //获得密钥
        return secretKey.getEncoded();
    }

    /**
     * HmacSHA1 消息摘要
     * @param data 待做摘要处理的数据
     * @param key 密钥
     * @return byte[] 消息摘要
     * @throws Exception
     */
    public static byte[] encodeHmacSHA(byte[] data, byte[] key) throws Exception{
        //还原密钥
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA1");
        //实例化Mac
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        //初始化Mac
        mac.init(secretKey);
        //执行消息摘要
        return mac.doFinal(data);
    }

    /**
     * 初始化 HmacSHA256 密钥
     * @return byte[] 密钥
     * @throws Exception
     */
    public static byte[] initHmacSHA256Key() throws Exception {
        //初始化KeyGenerator
        KeyGenerator kg = KeyGenerator.getInstance("HmacSHA256");
        //产生密钥
        SecretKey secretKey = kg.generateKey();
        //获得密钥
        return secretKey.getEncoded();
    }

    /**
     * HmacSHA256 消息摘要
     * @param data 待做摘要处理的数据
     * @param key 密钥
     * @return byte[] 消息摘要
     * @throws Exception
     */
    public static byte[] encodeHmacSHA256(byte[] data, byte[] key) throws Exception{
        //还原密钥
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256");
        //实例化Mac
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        //初始化Mac
        mac.init(secretKey);
        //执行消息摘要
        return mac.doFinal(data);
    }


    /**
     * 初始化 HmacSHA384 密钥
     * @return byte[] 密钥
     * @throws Exception
     */
    public static byte[] initHmacSHA384Key() throws Exception {
        //初始化KeyGenerator
        KeyGenerator kg = KeyGenerator.getInstance("HmacSHA384");
        //产生密钥
        SecretKey secretKey = kg.generateKey();
        //获得密钥
        return secretKey.getEncoded();
    }

    /**
     * HmacSHA384 消息摘要
     * @param data 待做摘要处理的数据
     * @param key 密钥
     * @return byte[] 消息摘要
     * @throws Exception
     */
    public static byte[] encodeHmacSHA384(byte[] data, byte[] key) throws Exception{
        //还原密钥
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA384");
        //实例化Mac
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        //初始化Mac
        mac.init(secretKey);
        //执行消息摘要
        return mac.doFinal(data);
    }
}

6.2.2 测试代码

 @Test
    public void testEncodeHmacMD5() throws Exception {
        String str = "HmacMD5消息摘要";
        //初始化密钥
        byte[] key = MACCoder.initHmacMD5Key();
        //获得摘要消息
        byte[] data1 = MACCoder.encodeHmacMD5(str.getBytes(), key);
        byte[] data2 = MACCoder.encodeHmacMD5(str.getBytes(), key);
        //校验
        assertArrayEquals(data1, data2);
    }

    @Test
    public void testEncodeHmacSHA() throws Exception {
        String str = "HmacSHA消息摘要";
        //初始化密钥
        byte[] key = MACCoder.initHmacSHAKey();
        //获得摘要消息
        byte[] data1 = MACCoder.encodeHmacSHA(str.getBytes(), key);
        byte[] data2 = MACCoder.encodeHmacSHA(str.getBytes(), key);
        //校验
        assertArrayEquals(data1, data2);
    }

你可能感兴趣的:(加密安全)