消息摘要算法(MDx)
消息摘要算法Message Digest Algorithm的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。MD5(1991年推出)是目前广泛使用的一种算法,由MD2、MD4一路发展而来。介绍MD相关算法并不是本文要点(ps:我也说不清...),本文只是介绍一下如何在Java中利用相关资源实现消息摘要。下面进入正题。

Java中JDK提供了MD2、MD5的实现,所以无需引入第三方Jar包即可实现消息摘要,只是JDK并未提供MD4的实现,所以MD4的实现需要借助第三方工具。

可以借助BouncyCastle, 其提供了MD2、MD4、MD5的实现。

另外还有一个比较常用的工具包:CommonsCodec,其对JDK的MD算法实现进行了进一步的封装,使之更易使用,使用它能减少一定代码量。

在网上可以找到相关的Jar包进行下载,也可以在Maven中配置依赖:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.58</version>
</dependency>

下面写个简单的测试:
package org.devsong;

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

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD4Digest;
import org.bouncycastle.crypto.digests.MD5Digest;

public class MessageDigestDemo {

    private static String src = "www.devsong.org";
    
    public static void main(String[] args) {
        //jdk提供相关算法测试,注:JDK并未提供 MD4 算法实现
        jdkMD2();
        jdkMD5();
        
        //查看CommonsCodec相关源码可以发现其对于MD的相关实现只是在JDK实现的基础上进一步的封装,使之更方便,所以其也就没有 MD4 的实现 
        ccMD2();
        ccMD5();
        
        //BouncyCastle完全实现了MD相关算法
        bcMD2();
        bcMD4();
        bcMD5();
    }

    /**
     * 自定义方法: byte 数组 转换为十六进制字符串
     * @param bytes 传入 byte 数组
     * @return 转换结果 String
     */
    public static String toHexString(byte[] bytes) {
        StringBuilder builder = new StringBuilder();
        for(byte b : bytes) {
            //考虑到小于16的正数在调用Integer.toHexString时前面的 0 是省略的,如10 --> a 而不是 0a, 但是MD算法结果中 0 是不能缺省的,所以手动在此加上
            if(b < 16 && b >= 0) {
                builder.append(0);
            }
            //进行十进制到十六进制的转换,负数的十六进制一般用补码表示,所以此处直接将负数补码(严格的说此处只是补码 的一部分,省略了高位)转化为十六进制
            builder.append( b>0   Integer.toHexString(b) : Integer.toHexString((-b ^ 0xff) + 1));
            
            //或者可以用如下方法,对于负数,转化为十六进制后截取后两位
            //builder.append( b>0   Integer.toHexString(b) : Integer.toHexString(b).substring(6, 8));
        }
        return builder.toString();
    }
    
    /**
     * jdk提供的 MD2 实现测试
     */
    public static void jdkMD2() {
        try {
            MessageDigest md = MessageDigest.getInstance("MD2");
            byte[] bytes = md.digest(src.getBytes());
            //自定义方法将byte数组转化为十六进制字符串
            //System.out.println(toHexString(bytes));    //593810bcff78631e3edf059d271699b5
            //调用commons.codec.binary.Hex的静态方法转化, 与上面的转化结果一致
            System.out.println("jdk MD2: " + Hex.encodeHexString(bytes));  //593810bcff78631e3edf059d271699b5
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * jdk提供的MD5实现测试
     */
    public static void jdkMD5() {
        try {
            //通过指定不同的字符串获得不同的对象,使用方法和上述 MD2 一致
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(src.getBytes());
            //System.out.println(toHexString(bytes));
            System.out.println("jdk MD5: " + Hex.encodeHexString(bytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * Commons Codec 提供的MD2测试
     */
    public static void ccMD2() {
        System.out.println("ccMD2: " + DigestUtils.md2Hex(src.getBytes()));
    }

    /**
     * Commons Codec 提供的MD5测试
     */
    public static void ccMD5() {
        System.out.println("ccMD5: " + DigestUtils.md5Hex(src.getBytes()));
    }
    
    /**
     * BouncyCastle 提供的MD2实现测试
     */
    public static void bcMD2() {
        //获取对应算法的实现对象
        Digest digest = new MD2Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] bytes = new byte[digest.getDigestSize()];
        digest.doFinal(bytes, 0);
        //System.out.println(toHexString(bytes));
        //BouncyCastle同样提供了byte数组转十六进制字符串的相关方法
        System.out.println("bcMD2: " + org.bouncycastle.util.encoders.Hex.toHexString(bytes));
    }
    
    /**
     * BouncyCastle 提供的MD4实现测试
     * 使用方法和MD2一致
     */
    public static void bcMD4() {
        //获取对应算法的实现对象
        Digest digest = new MD4Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] bytes = new byte[digest.getDigestSize()];
        digest.doFinal(bytes, 0);
        //System.out.println(toHexString(bytes));
        System.out.println("bcMD4: " + org.bouncycastle.util.encoders.Hex.toHexString(bytes));
    }
    
    /**
     * BouncyCastle 提供的MD5实现测试
     */
    public static void bcMD5() {
        Digest digest = new MD5Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] bytes = new byte[digest.getDigestSize()];
        digest.doFinal(bytes, 0);
        //System.out.println(toHexString(bytes));
        System.out.println("bcMD5: " + org.bouncycastle.util.encoders.Hex.toHexString(bytes));
    }
}

执行结果:
jdk MD2: 593810bcff78631e3edf059d271699b5
jdk MD5: 23184157d21d85b6481b1125c60d821e
ccMD2: 593810bcff78631e3edf059d271699b5
ccMD5: 23184157d21d85b6481b1125c60d821e
bcMD2: 593810bcff78631e3edf059d271699b5
bcMD4: 012e69f3eeee611a0f9ae6c60b10781a
bcMD5: 23184157d21d85b6481b1125c60d821e
It's
欢迎访问本站,欢迎留言、分享、点赞。愿您阅读愉快!
*转载请注明出处,严禁非法转载。
https://www.devsong.org
QQ留言 邮箱留言
头像
引用:
取消回复
提交
涂鸦
涂鸦
热门