哈希算法总结

目录

一、概述

二、哈希碰撞

三、常用哈希算法及其用途

1.加密文字(以MD5为例,其他算法更改加密方法即可(除RipeMD-160)

 2.加密图片

3.防止彩虹表攻击

四、RipeMD-160加密算法

五、使用Hash算法工具类进行加密(多次调用时减少重复)

总结:


一、概述

        哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
哈希算法最重要的特点就是:
● 相同的输入一定得到相同的输出;
● 不同的输入大概率得到不同的输出。
所以,哈希算法的目的:为了验证原始数据是否被篡改

二、哈希碰撞

        哈希碰撞是指:两个不同的输入得到了相同的输出。例如:

"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0

"通话".hashCode(); // 0x11ff03
"重地".hashCode(); // 0x11ff03

        碰撞无法避免,我们需要做的是减少碰撞发生的概率。一个安全的哈希算法必须满足:

● 碰撞概率低;
● 不能猜测输出。

三、常用哈希算法及其用途

        哈希算法,根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。
        常用的哈希算法有:

算法输出长度(位)输出长度(字节)
MD5128bits16bytes
SHA-1160bits20bytes
RipeMD-160160bits20bytes
SHA-256256bits32bytes
SHA-512512bits64bytes

          用途:

1.校验下载文件

因为相同的输入永远会得到相同的输出,因此,如果输入被修改了,得到的输出就会不同。我们在网站上下载软件的时候,经常看到下载页显示的MD5哈希值:

2.存储用户密码

哈希算法的另一个重要用途是存储用户口令。如果直接将用户的原始口令存放到数据库中,会产生极大的安全风险:
● 数据库管理员能够看到用户明文口令;
● 数据库数据一旦泄漏,黑客即可获取用户明文口令。

1.加密文字(以MD5为例,其他算法更改加密方法即可(除RipeMD-160)

        使用MessageDigest抽象类时,首先根据哈希算法获取一个MessageDigest实例,然后,反复调用update(byte[])输入数据。当输入结束后,调用digest()方法获得byte[]数组表示的摘要,最后,把它转换为十六进制的字符串。代码示例如下:

//MD5加密算法
public class Demo6 {
    public static void main(String[] args) {
        try {
            //创建基于MD5算法的消息摘要对象
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            //更新原始数据
            md5.update("今天星期一".getBytes());
            md5.update("又是新的一天".getBytes());
            //获取加密后的结果
            byte[] digestBytes = md5.digest();
            System.out.println("加密后(字节数组):" + Arrays.toString(digestBytes));
            System.out.println("加密后(16进制字符串):" + HashTools.bytesToHex(digestBytes));
            System.out.println("加密后长度:" + digestBytes.length);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

运行结果如下:

 2.加密图片

        首先,创建基于MD5加密算法的消息摘要对象,然后把图片读成字节数组,再利用MD5进行加密处理。

//按照MD5算法对图片进行加密
public class Demo7 {
    public static void main(String[] args) {
        try {
            //图片的原始字节内容
            byte[] imgBuf = Files.readAllBytes(Paths.get("C:\\Users\\Lenovo\\Pictures\\Screenshots\\1.png"));
            //创建基于MD5算法的消息摘要对象
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            //原始字节内容(图片)
            md5.update(imgBuf);
            byte[] imgDigest = md5.digest();
            //获取加密摘要
            System.out.println("加密后(字节数组):" + Arrays.toString(imgBuf));
            System.out.println("加密后(16进制字符串:)" + HashTools.bytesToHex(imgDigest));
            System.out.println("加密后长度:" + imgDigest.length);          //MD5 算法的固定输出长度为16个字节
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

3.防止彩虹表攻击

        使用哈希口令时,还要注意防止彩虹表攻击。
什么是彩虹表呢?上面讲到了,如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法。然而黑客并不笨,暴力穷举会消耗大量的算力和时间。但是,如果有一个预先计算好的常用口令和它们的MD5的对照表,这个表就是彩虹表。如果用户使用了常用口令,黑客从MD5一下就能反查到原始口令:

常用口令MD5
hello123f30aa7a662c728b7407c54ae6bfd27d1
1234567825d55ad283aa400af464c76d713c07ad
passw0rdbed128365216c019988915ed3add75fb
19700101570da6d5277a646f6552b8832012f5dc
wbjxxmy11d7a82f45f6a176fd9d5c100ccab40a

        当然,我们也可以采取特殊措施来抵御彩虹表攻击:对每个口令额外添加随机数,这个方法称之为加盐(salt):
digest = md5(salt + inputPassword)

//通过随机加盐解决彩虹表攻击问题
public class Demo8 {
    public static void main(String[] args) {

        try {
            //创建基于MD5算法的消息摘要对象
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            //原始密码
            md5.update("wbjxxmy".getBytes());

            //产生随机盐值
            String salt = UUID.randomUUID().toString().substring(0,4);
            md5.update(salt.getBytes());
            //计算加密结果,MD5的输出结果为16个字节(32个字符)
            String digest = HashTools.bytesToHex(md5.digest());
            System.out.println("加密后:" + digest);

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }

    }
}

四、RipeMD-160加密算法

         1.RipeMD-160算法是第三方开源加密算法,使用之前需要导入bcprov-jdk15on-1.70.jar包,地址:bouncycastle.orghttps://www.bouncycastle.org/latest_releases.html

        2.创建基于RipeMD-160算法的消息摘要对象之前,先注册BouncyCastleProvider通知类,将提供的消息摘要算法注册至Security。(其他与MD5加密算法相同)

//使用第三方开源库提供的RipeMD160消息摘要算法实现
public class Demo13 {
    public static void main(String[] args) {
        //注册BouncyCastleProvider通知类
        //将提供的消息摘要算法注册至Security
        Security.addProvider(new BouncyCastleProvider());
        try {
            //创建基于RipeMD160算法的消息摘要对象
            MessageDigest ripeMD160 = MessageDigest.getInstance("RipeMD160");
            //原始密码
            ripeMD160.update("wbjxxmy".getBytes());
            //获取消息摘要(加密)
            byte[] result = ripeMD160.digest();
            //消息摘要的字节长度和内容
            System.out.println("加密结果(字节长度):" + result.length);   //160位=20字节
            System.out.println("加密结果(字节内容):" + Arrays.toString(result));

            //16进制内容字符串
            String hex = new BigInteger(1,result).toString(16);
            System.out.println("加密结果(字符串长度):" + hex.length());
            System.out.println("加密结果(字符串内容):" + hex);

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

五、使用Hash算法工具类进行加密(多次调用时减少重复)

        在每次进行加密时,会重复调用MessageDigest()方法创建对象,更新加密信息,调用digest()方法加密,所以可以把重复的部分写入HashTools工具类当中。

//Hash算法(消息摘要算法)工具类
public class HashTools {
    //消息摘要对象
    private static MessageDigest digest;
    //构造方法私有
    private HashTools(){}
    //按照MD5进行消息摘要计算(哈希计算)
    public static String digestMD5(String source) throws NoSuchAlgorithmException {
        digest = MessageDigest.getInstance("MD5");
        return handler(source);
    }
    //按照SHA-1进行消息摘要计算(哈希计算)
    public static String digestSHA1(String source) throws NoSuchAlgorithmException {
        digest = MessageDigest.getInstance("SHA-1");
        return handler(source);
    }
    //通过消息摘要对象,处理加密内容
    private static String handler(String source){
        digest.update(source.getBytes());
        byte[] bytes = digest.digest();
        String hash = bytesToHex(bytes);
        return hash;
    }
    //将字节值转换为2位十六进制字符串
    public static String bytesToHex(byte[] bytes){
        StringBuilder ret = new StringBuilder();
        for (byte b:bytes
             ) {
            ret.append(String.format("%02x",b));    //转换成16进制的两位字节形式
        }
        return ret.toString();
    }
}

         调用HashTools工具类,完成加密操作:

//通过自定义工具类,完成对应加密处理
public class Demo9 {
    public static void main(String[] args) {
        try {
            //MD5加密
            String MD5 = HashTools.digestMD5("wbjxxmy");
            System.out.println("MD5=" + MD5);
            //SHA-1加密
            String SHA1 = HashTools.digestSHA1("wbjxxmy");
            System.out.println("SHA1=" + SHA1);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

总结:

● 哈希算法可用于验证数据完整性,具有防篡改检测的功能;
● 常用的哈希算法有MD5、SHA-1等;
● 用哈希存储口令时要考虑彩虹表攻击。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

起个有趣的名字好难

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

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

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

打赏作者

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

抵扣说明:

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

余额充值