zoukankan      html  css  js  c++  java
  • 廖雪峰Java10加密与安全-3摘要算法-1MD5

    1.摘要算法

    1.1 摘要算法(哈希算法/Hash/数字指纹):

    • 计算任意长度数据的摘要(固定长度)
    • 相同的输入数据始终得到相同的输出
    • 不同的输入尽量得到不同的输出

    1.2 摘要算法目的:

    • 验证数据和原始数据是否一致,被篡改

    1.3.java的Object.hashCode()方法就是一个摘要算法:

    • 输入:任意数据
    • 输出:固定长度数据(int, byte[4])
    • 相同的输入得到相同的输出:重写equals方法时,也要正确的复写hashCode方法。

    1.4.碰撞

    两个不同的输入得到了相同的输出,仅做示例

        hash("abc") = 0x12345678 
        hash("xyz") = 0x12345678
    

    原因:哈希算法是将一个无限的输入集合映射到一个有限的输入集合。碰撞是不能避免的,因为输出的字节长度是固定的,而输入的字节长度是不固定的。所以哈希算法是把一个无限的输入集合映射到一个有限的输出集合。
    假设输出2个字节的摘要,1个字节8位,2个字节16位,即所有的输出在16个0到16个1之间,即2^16=65536。将无限的输入映射到输出集合中,肯定有不同的输入获得相同输出的情况,即碰撞。

    1.5 Hash算法的安全性:

    一个好的Hash算法:

    • 碰撞率要低
    • 不能根据输入猜测输出
      * 如hashA("java001") = "123456",hashA("java002") = "123457"。可能推出hashA("java003") = "123458"
    • 输入的任意一个bit的变化会造成输出完全不同
      * 如hashA("java001") = "123456",hashA("java002") = "580645"。可能推出hashA("java003") = ?
    • 很难从输出反推输入(只能暴力穷举)

    1.6 常用的摘要算法:

    算法 输出长度:位数 输出长度:字节数
    MD5 128 bits 16bytes
    SHA-1 160bits 20bytes
    SHA-256 256bits 32bytes
    PipeMd-160 160bits 20bytes

    2 MD5算法

    Java使用MD5非常简单

    //示例代码
    import java.security.MessageDigest;
    ...
            MessageDigest md = new MessageDigest.newInstance("MD5");
            //反复调用update输入数据
            md.update(data1);
            md.update(data2);
            ...
            byte[] result = md.digest();//获取长度为16的byte数组
    

    输入数据可以分片操作

    import java.security.MessageDigest;
    import java.util.Arrays;
    
    public class SplitString {
        public static void main(String[] args) throws Exception{
            getMD5("helloworld");
            String[] ss = {"hello","world"};
            getMD5(ss);
        }
        static void getMD5(String s) throws Exception{
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(s.getBytes());
            byte[] result =  md.digest();
            System.out.println(Arrays.toString(result));
        }
        static void getMD5(String[] s) throws Exception{
            MessageDigest md = MessageDigest.getInstance("MD5");
            for(String si:s){
                md.update(si.getBytes());
            }
            byte[] result =  md.digest();
            System.out.println(Arrays.toString(result));
        }
    }
    

    2.1 MD5用途

    • 验证文件完整性
    • MD5存储用户口令
    • 系统不存储用户原始口令
    • 系统存储用户原始口令的MD5

    如何判断用户口令是否正确

    • 系统计算用户输入的原始口令的MD5并与数据库存储的MD5对比
      * 相同:口令正确
      * 不相同:口令错误

    使用MD5要注意防止彩虹表攻击

    抵御彩虹表攻击:

    • 对每个口令额外添加随机数salt
      * md5(password)
      * md5(salt+password)

    3.代码示例

    import java.math.BigInteger;
    import java.security.MessageDigest;
    
    public class SplitString {
        public static byte[] toMD5(byte[] input){
            MessageDigest md;
            try{
                md = MessageDigest.getInstance("MD5");
            }catch (Exception e){
                throw new RuntimeException(e);
            }
            md.update(input);
            return md.digest();//返回MD5
        }
        public static void main(String[] args) throws Exception {
            String s = "MD5摘要算法测试";
            byte[] r = toMD5(s.getBytes("UTF-8"));//先将字符串转化为字节数组
            System.out.println(String.format("%032x",new BigInteger(1,r)));
            System.out.println(String.format("%040x",new BigInteger(1,r)));//不足40位,前面补0
            System.out.println(String.format("%40x0",new BigInteger(1,r)));//后面加0
        }
    }
    
    import java.math.BigInteger;
    import java.security.MessageDigest;
    
    public class SplitString {
        public static byte[] toMD5(byte[] input){
            MessageDigest md;
            try{
                md = MessageDigest.getInstance("MD5");
            }catch (Exception e){
                throw new RuntimeException(e);
            }
            md.update(input);
            return md.digest();//返回MD5
        }
        public static void main(String[] args) throws Exception {
            String s = "helloworld";
            String salt = "Random salt";
            byte[] r = toMD5((salt+s).getBytes("UTF-8"));//先将字符串转化为字节数组
            System.out.println(String.format("%032x",new BigInteger(1,r)));
            System.out.println(String.format("%040x",new BigInteger(1,r)));
            System.out.println(String.format("%40x0",new BigInteger(1,r)));
        }
    }
    

    4.总结:

    • MD5是一种常用的哈希算法,输出128bits/16bytes
    • 常用于验证数据完整性
    • 用于存储口令时要考虑彩虹表攻击
  • 相关阅读:
    videojs 隐藏videobar
    nw 系统托盘的添加方式,以及ajax失效问题
    nw 注册快捷键
    bg-script 错误信息显示,以及global
    input 文件上传
    git stash,git cherry-pick
    安装Laravel
    nw + iframe嵌入page 滚动条问题
    require('nw.gui') 失效问题
    dell 交换机 双链路冗余
  • 原文地址:https://www.cnblogs.com/csj2018/p/10828688.html
Copyright © 2011-2022 走看看