密码技术学习(4.2)- 消息摘要函数(散列函数)在Java中的使用

文章目录

MD算法家族

MD5Test

SHA算法家族

SHACoder

SHACoderTest

MAC算法家族

MACCoder

MACCoderTest

关于本章内容,参考了一下书籍和文章

本系列其他文章


MD算法家族

MD家族有很多算法,今天我们只认识一下MD5算法。MD5算法最终会产生一个128位(16字节)的散列值。

MD5Test

import static org.junit.Assert.assertArrayEquals;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
import org.junit.Test;

/**
 * MD5 算法测试
 * 
 * @author shaozuo
 * @date 2018/06/29
 */
public class MD5Test {
    private static final int MD5_HASH_BYTE_LENGTH = 16;//16*8=128

    private static String key = "Java加密与解密的艺术";

    @Test
    public void tesJdkMd5() throws NoSuchAlgorithmException {
        byte[] data1 = jdkMd5(key);
        byte[] data2 = jdkMd5(key);
        System.out.println(Hex.encodeHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(MD5_HASH_BYTE_LENGTH, data1.length);
    }

    @Test
    public void testCodecMd5() {
        byte[] data1 = codecMd5(key);
        byte[] data2 = codecMd5(key);
        System.out.println(Hex.encodeHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(MD5_HASH_BYTE_LENGTH, data1.length);
    }

    @Test
    public void testMd5() {
        byte[] data1 = bouncyCastleMd5(key);
        byte[] data2 = bouncyCastleMd5(key);
        System.out.println(Hex.encodeHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(MD5_HASH_BYTE_LENGTH, data1.length);
    }

    /**
     * codec 实现MD5加密
     */
    private static byte[] codecMd5(String key) {
        return DigestUtils.getMd5Digest().digest(key.getBytes(Charsets.UTF_8));
    }

    /**
     * Bouncy Castle实现MD5加密
     */
    private static byte[] bouncyCastleMd5(String key) {
        Digest digest = DigestFactory.createMD5();
        digest.update(key.getBytes(Charsets.UTF_8), 0, key.getBytes().length);
        byte[] md5Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(md5Bytes, 0);
        return md5Bytes;
    }

    private static byte[] jdkMd5(String key) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        return md5.digest(key.getBytes(Charsets.UTF_8));
    }
}

SHA算法家族

与MD算法相比,SHA算法的摘要长度更长,安全性更高。 
不同的消息,产生的消息摘要差异性概率更高。

SHACoder

import java.security.GeneralSecurityException;
import java.security.MessageDigest;

/**
 * SHA 算法组件
 * 
 * @author shaozuo
 * @date 2018/08/03
 */
public final class SHACoder {
    private SHACoder() {
    }

    /**
     * SHA-1 消息摘要算法 <br>
     * 摘要长度 160位
     * 
     * 
     * @param data
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encodeSHA(byte[] data) throws GeneralSecurityException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        return md.digest(data);
    }

    /**
     * SHA-256 消息摘要算法
     * 
     * @param data
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encodeSHA256(byte[] data) throws GeneralSecurityException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        return md.digest(data);
    }

    /**
     * SHA-384 消息摘要算法
     * 
     * @param data
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encodeSHA384(byte[] data) throws GeneralSecurityException {
        MessageDigest md = MessageDigest.getInstance("SHA-384");
        return md.digest(data);
    }

    /**
     * SHA-512 消息摘要算法
     * 
     * @param data
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encodeSHA512(byte[] data) throws GeneralSecurityException {
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        return md.digest(data);
    }

}

SHACoderTest

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import java.security.GeneralSecurityException;

import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

public class SHACoderTest {

    String input = "SHA 算法测试";

    @Test
    public void test() throws GeneralSecurityException {
        byte[] data1 = SHACoder.encodeSHA(input.getBytes());
        byte[] data2 = SHACoder.encodeSHA(input.getBytes());
        System.out.println(Hex.toHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(20, data1.length);
    }

    @Test
    public void testSHA512() throws GeneralSecurityException {
        byte[] data1 = SHACoder.encodeSHA512(input.getBytes());
        byte[] data2 = SHACoder.encodeSHA512(input.getBytes());
        System.out.println(Hex.toHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(64, data1.length);
    }

}

MAC算法家族

MAC(Message Authentication Code,消息认证码)是含有密钥的消息摘要算法,兼容了MD和SHA算法的特性。MD系列的算法有HmacMD2、HmacMD4和HmacMD5三种算法;SHA系列算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384和HmacSHA512五种算法。MAC计算后的消息摘要长度与参与实现的算法相关。

MACCoder

只是使用HmacMD5和HmacSHA512两种,其他算法类似。

import java.security.GeneralSecurityException;

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

/**
 * MAC 算法组件
 * 
 * @author shaozuo
 * @date 2018/08/06
 */
public final class MACCoder {
    private static final String HMAC_MD5 = "HmacMD5";
    private static final String HMAC_SHA512 = "HmacSHA512";

    private MACCoder() {
    }

    /**
     * 初始化HmacMD5密钥
     * 
     * @return
     * @throws Exception
     */
    public static byte[] initHmacMD5Key() throws GeneralSecurityException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(HMAC_MD5);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * HmacMD5 消息摘要
     * 
     * @param data
     *            待做消息摘要数据
     * @param key
     *            密钥
     * @return byte[] 消息摘要
     * @throws Exception
     */
    public static byte[] encodeHmacMD5(byte[] data, byte[] key) throws GeneralSecurityException {
        SecretKey secretKey = new SecretKeySpec(key, HMAC_MD5);
        Mac mac = Mac.getInstance(HMAC_MD5);
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    /**
     * 初始化HmacSHA512密钥
     * 
     * @return
     * @throws Exception
     */
    public static byte[] initHmacSHA512Key() throws GeneralSecurityException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(HMAC_SHA512);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * HmacSHA512 消息摘要
     * 
     * @param data
     *            待做消息摘要数据
     * @param key
     *            密钥
     * @return byte[] 消息摘要
     * @throws Exception
     */
    public static byte[] encodeHmacSHA512(byte[] data, byte[] key) throws GeneralSecurityException {
        SecretKey secretKey = new SecretKeySpec(key, HMAC_SHA512);
        Mac mac = Mac.getInstance(HMAC_SHA512);
        mac.init(secretKey);
        return mac.doFinal(data);
    }
}

MACCoderTest

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import java.security.GeneralSecurityException;

import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

public class MACCoderTest {

    String input = "MAC 算法测试";

    @Test
    public void test() throws GeneralSecurityException {
        byte[] key = MACCoder.initHmacMD5Key();
        byte[] data1 = MACCoder.encodeHmacMD5(input.getBytes(), key);
        byte[] data2 = MACCoder.encodeHmacMD5(input.getBytes(), key);
        System.out.println(Hex.toHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(16, data1.length);
    }

    @Test
    public void testMAC512() throws GeneralSecurityException {
        byte[] key = MACCoder.initHmacSHA512Key();
        byte[] data1 = MACCoder.encodeHmacSHA512(input.getBytes(), key);
        byte[] data2 = MACCoder.encodeHmacSHA512(input.getBytes(), key);
        System.out.println(Hex.toHexString(data1));
        assertArrayEquals(data1, data2);
        assertEquals(64, data1.length);
    }

}

关于本章内容,参考了一下书籍和文章

  1. Java加密与解密的艺术 链接
  2. 消息摘要算法 百度百科
  3. Jdk支持的算法官方文档
  4. MD5 百度百科
  5. SHA家族百度百科
  6. MAC算法百度百科

本系列其他文章

密码技术学习系列文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值