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

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注册的流程
在这里插入图片描述
下图是使用MD登录验证的流程
在这里插入图片描述

3. MD算法家族

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

算法摘要长度备注
MD2128Bouncy Castle
MD5128Java6
MD4128Bouncy 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:lhzheng@grandstream.cn
 * 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算法的消息传递模型
在这里插入图片描述

4.2 SHA实现

Java及Bouncy Castle实现细节如下

算法摘要长度备注
SHA-1160Java 6
SHA-256256Java 6
SHA-384384Java 6
SHA-512512Java 6
SHA-224224Bouncy 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:lhzheng@grandstream.cn
 * 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 模型分析

在这里插入图片描述

6.2 MAC算法实现

实现细节如下所示

算法摘要长度备注
HmacMD5128Java
HmacSHA1160Java
HmacSHA256256Java
HmacSHA384384Java
HmacSHA512512Java
HmacMD2128Bouncy Castle
HmacMD4128Bouncy Castle
HmacSHA224224Bouncy 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:lhzheng@grandstream.cn
 * 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);
    }
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值