shiro中MessageDigest根据盐值计算md5

Posted 张侦毅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shiro中MessageDigest根据盐值计算md5相关的知识,希望对你有一定的参考价值。

MessageDigest简介

  java.security.MessageDigest类用于为应用程序提供信息摘要算法的功能,如 MD5SHA 算法。简单点说就是用于生成散列码。信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值。

源码示例

  在下面的示例中,抽取的是shiro中的SimpleHash类源码使用的是shiro中的MessageDigest,通过对名为adminusername进行盐值计算,然后依据此盐值对密码123456进行md5计算。

  源码如下:

@Slf4j
public class MessageDigestTest 

    /**
     * 盐值计算
     * @param username 用户名
     * @return byte[] 盐值byte数组
     */
    public byte[] getSalt(String username)
        // 计算盐值
        ByteSource byteSource = ByteSource.Util.bytes(username);
        return byteSource.getBytes();
    

    /**
     * 将字符串转换成byte数组
     * @param str 输入字符串
     * @return byte[]
     */
    private byte[] getByte(String str) 
        return str.getBytes();
    

    /**
     * 测试md5盐值加密算法
     * 用户admin,密码123456
     * 加密后的结果:e0b141de1c8091be350d3fc80de66528
     */
    @Test
    public void testMD5()
        // 计算次数
        Integer hashIterations = 4;
        try 
            // 装载md5加密方法
            MessageDigest digest = MessageDigest.getInstance("md5");
            // 计算用户盐值
            byte[] salt = getSalt("admin");
            // 将密码转换成byte数组
            byte[] bytes = getByte("123456");
            // 如果盐值不为空,则MessageDigest加载盐值
            if (salt != null) 
                digest.reset();
                digest.update(salt);
            
            // 执行md5运算
            byte[] hashed = digest.digest(bytes);
            int iterations = hashIterations - 1; //already hashed once above
            //iterate remaining number:
            for (int i = 0; i < iterations; i++) 
                digest.reset();
                hashed = digest.digest(hashed);
            
            // 将byte数组转换成字符串
            String result = byteToString(hashed);
            // 在控制台中打印加密后的md5字符串
            log.info("md5加密结果:",result);
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
        
    

    /**
     * 将byte数组转换成字符串
     * @param hashed 加密字符串
     * @return String
     */
    private String byteToString(byte[] hashed) 
        // 创建字符串StringBuffer
        StringBuffer sb = new StringBuffer();
        // 创建缓存
        String temp = null;
        // 循环遍历拼接字符串
        for(int i = 0,hashedLenth = hashed.length; i < hashedLenth; i ++)
            temp = Integer.toHexString(0xFF & hashed[i]);
            sb.append(temp);
        
        return sb.toString();
    


  上面中,源码的计算结果为:e0b141de1c8091be350d3fc80de66528

分析

MessageDigest的实例化

  从上面的示例中,我们可以看出,MessageDigest的实例化方法为:

MessageDigest digest = MessageDigest.getInstance("md5");

  在实例化的同时,我们需要为其指定加密方式,如上面,我们指定的加密方式为md5

MessageDigest接收被加密数据

  MessageDigest接收被加密数据方式如下:

digest.update(salt);

  为了避免之前接收的被加密数据对现在所造成的影响,因而这里加入了清空之前接收的被加密数据方法。

digest.reset();

  而MessageDigest执行的加密方法为:

byte[] hashed = digest.digest(bytes);

  虽然说在源码中,在此之前也加入了digest.reset();操作,不过经过实测,删掉此处的代码其也并不影响结果的正确性,换言之,对于digest.digest(bytes)的前序操作digest.reset();可加可不加,在此处并不会影响程序的执行结果。

  这里需要注意的是,MessageDigest所接收的数据,无论是盐值,还是密码,均是byte[]格式。

  而被接收的数据如果长度比较长,可以通过重复执行多次digest.update(salt);,依次将其添加进来;同样的,MessageDigest对于被加密对象,也可以执行多次加密操作,即可以执行多次digest.digest(bytes)操作,这样进而增加了加密密码的强度。

  而在上面的例子中hashIterations 表示的是加密的迭代次数,在shiro的源码中,默认执行4次加密操作。

以上是关于shiro中MessageDigest根据盐值计算md5的主要内容,如果未能解决你的问题,请参考以下文章

Shiro学习——MD5加密与盐值

MD5盐值加密

Shiro___加密加盐迭代

shiro+密码匹配器验证登陆

摘要算法MessageDigest

MessageDigest的功能及用法