美文网首页
05-(转载)MessageDigest类与MD5算法

05-(转载)MessageDigest类与MD5算法

作者: Michael_748c | 来源:发表于2018-02-11 10:13 被阅读0次

    转载地址:https://juejin.im/post/5a7fa2e06fb9a063435ed40b

    MessageDigest类与MD5算法

    (一)基本介绍

    Java的MessageDigest 类 可以提供MD5算法或SHA算法用于计算出数据的摘要;它接收任意大小的数据,并输出计算后的固定长度的哈希值。这个输出的哈希值就是我们所说的信息摘要。

    MD5算法得到的摘要是固定为 128 bit 的二进制串(一堆0和1,一共128个),为了更友好的表示摘要,一般都将 128位的二进制串 转为 32个16进制位16个16进制位 如下:

    栏目1 栏目2
    原始数据 1234567890
    16位小写摘要 f82d132f9bb018ca
    16位大写摘要 F82D132F9BB018CA
    32位小写摘要 e807f1fcf82d132f9bb018ca6738a19f
    32位大写摘要 E807F1FCF82D132F9BB018CA6738A19F

    (二)16位的摘要?

    MD5算法得到的摘要固定长度位 128 bit 也就是32位,那么怎么还有16的摘要呢?
    其实从上面的表格中可以看出,16位的摘要是取32位的摘要值的中间部分,即32位摘要中第8~24位的片段。

    (三)MessageDigest类计算MD5摘要的步骤

    1,创建MessageDigest对象

    public static MesageDigest getInstance(String algorithm);
    

    算法名不区分大小写,所以下面的写法都是正确的:

    MesageDigest getInstance("MD5");
    MesageDigest getInstance("md5");
    MesageDigest getInstance("mD5");
    

    2,向MessageDigest传送要计算的数据

    该步骤就是调用下面的某个方法来完成数据的传递。

    public void update(byte input);
    public void update(byte[] input);
    public void update(byte[] input, int offset, int len);
    

    3,计算摘要

    最后调用下面的某个方法来计算摘要。

    public byte[] digest();
    public byte[] digest(byte[] input);
    public int digest(byte[] buf,int offset,int len);
    

    4,将摘要转为16进制位的字符串

    为了更友好的表示摘要,一般都将 128位的二进制串 转为 32个16进制位16个16进制位 ,并以字符串的形式表示。

    摘要一般以字符串的形式展示,所以在WEB应用中,用于表示密码的MD5摘要的数据库字段一般设置为String类型String password(虽然字段名字面意思表示账户密码,但实际上只是账户密码的MD5摘要)。

    (四)基于MessageDigest类的MD5工具类实现

    1,MD5工具类完整代码

    import java.security.MessageDigest;
    
    public class MD5Util {
    
        private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
    
        /**
         * 将1个字节(1 byte = 8 bit)转为 2个十六进制位
         * 1个16进制位 = 4个二进制位 (即4 bit)
         * 转换思路:最简单的办法就是先将byte转为10进制的int类型,然后将十进制数转十六进制
         */
        private static String byteToHexString(byte b) {
            // byte类型赋值给int变量时,java会自动将byte类型转int类型,从低位类型到高位类型自动转换
            int n = b;
    
            // 将十进制数转十六进制
            if (n < 0)
                n += 256;
            int d1 = n / 16;
            int d2 = n % 16;
    
            // d1和d2通过访问数组变量的方式转成16进制字符串;比如 d1 为12 ,那么就转为"c"; 因为int类型不会有a,b,c,d,e,f等表示16进制的字符
            return hexDigits[d1] + hexDigits[d2];
        }
    
        /**
         * 将字节数组里每个字节转成2个16进制位的字符串后拼接起来
         */
        private static String byteArrayToHexString(byte b[]) {
            StringBuffer resultSb = new StringBuffer();
            for (int i = 0; i < b.length; i++){
                resultSb.append(byteToHexString(b[i]));
            }
            return resultSb.toString();
        }
    
        /**
         * MD5算法,统一返回大写形式的摘要结果,默认固定长度是 128bit 即 32个16进制位
         * String origin :需要进行MD5计算的字符串
         * String charsetname :MD5算法的编码
         */
        private static String MD5_32(String origin, String charsetname) {
            String resultString = null;
            try {
                // 1,创建MessageDigest对象
                MessageDigest md = MessageDigest.getInstance("MD5");
                // 2,向MessageDigest传送要计算的数据;传入的数据需要转化为指定编码的字节数组
                md.update(origin.getBytes( charsetname ));
                // 3,计算摘要
                byte[] bytesResult = md.digest();
    
                // 第2步和第3步可以合并成下面一步
                // byte[] bytesResult = md.digest(origin.getBytes(charsetname));
    
                // 4,将字节数组转换为16进制位
                resultString = byteArrayToHexString( bytesResult );
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 统一返回大写形式的字符串摘要
            return resultString.toUpperCase();
    
        }
    
        /**
         * 获取 16位的MD5摘要,就是截取32位结果的中间部分
         */
        private static String MD5_16(String origin, String charsetname) {
            return MD5_32(origin, charsetname).substring(8,24);
        }
    
        public static void main(String[] args){
            String origin = "1234567890";
    
            // 默认MD5计算得到128 bit的摘要,即32个 16进制位
            String result_32 = MD5_32(origin, "utf-8");
            System.out.println(result_32);  // E807F1FCF82D132F9BB018CA6738A19F
    
            // 默认MD5计算得到即16个 16进制位
            String result_16 = MD5_16(origin, "utf-8");
            System.out.println(result_16);  // F82D132F9BB018CA
        }
    }
    

    2,没有调用update方法?

    在很多时候,我们经常看到类似下面的写法:

    byte[] bytesResult = md.digest(origin.getBytes(charsetname));
    

    在这种写法中并没有代码显式地调用update方法,但跟下面的写法是一样的,实际上也调用了update方法:

    // 2,向MessageDigest传送要计算的数据;传入的数据需要转化为指定编码的字节数组
    md.update(origin.getBytes( charsetname ));
    // 3,计算摘要
    byte[] bytesResult = md.digest();
    

    查看该digest(byte[] input)方法的源码,可以看到该方法其实就是将第2步和第3步封装成一个函数而已。

    public byte[] digest(byte[] input) {
        update(input);
        return digest();
    }
    

    相关文章

      网友评论

          本文标题:05-(转载)MessageDigest类与MD5算法

          本文链接:https://www.haomeiwen.com/subject/zfkftftx.html