“MD5”加密算法全解析


“MD5”加密算法全解析

    大家好,我们现在来讲解关于加密方面的知识,说到加密我认为不得不提MD5,因为这是一种特殊的加密方式,它到底特殊在哪,现在我们就开始学习它

    全称:message-digest algorithm 5
    翻译过来就是:信息 摘要 算法 5

    1.特点

    • 1.长度固定:

      不管多长的字符串,加密后长度都是一样长
      作用:方便平时信息的统计和管理

    • 2.易计算:

      字符串和文件加密的过程是容易的.
      作用: 开发者很容易理解和做出加密工具

    • 3.细微性

      一个文件,不管多大,小到几k,大到几G,你只要改变里面某个字符,那么都会导致MD5值改变.
      作用:很多软件和应用在网站提供下载资源,其中包含了对文件的MD5码,用户下载后只需要用工具测一下下载好的文件,通过对比就知道该文件是否有过更改变动.

    • 4.不可逆性

      你明明知道密文和加密方式,你却无法反向计算出原密码.
      作用:基于这个特点,很多安全的加密方式都是用到.大大提高了数据的安全性


    2.后续讲解

    • 关于撞库破解:

      这是概率极低的破解方法,原理就是:

      1.建立一个大型的数据库,把日常的各个语句,通过MD5加密成为密文,不断的积累大量的句子,放在一个庞大的数据库里.

      2.比如一个人拿到了别人的密文,想去查询真实的密码,就需要那这个密文去到提供这个数据库的公司网站去查询.

      这就是撞库的概念.


    3.关于MD5加盐:

    比如我的银行密码是”12345”

    1.得到的MD5是:827ccb0eea8a706c4c34a16891f84e7b

    2.一个人截取到这个密文,那么通过撞库肯定容易撞出12345.

    3.我们要做的就是加盐,银行密码还是”12345”,然后我把银行密码加上我特定的字符串才计算MD5
    所以密码还是那个密码,但是变成求”12345密码加密987”的MD5值,然后再得到MD5,那么这个MD5起码可以确认那个数据库不会有.


    说了那么多我们开始我们的MD5工具的制作

    我们一般加密都是加密字符串或者文件,所以我们的工具就有加密字符串和文件的两种方法,两个方法同名,通过重载完成

    1.加密字符串

    逻辑思维:

    • 1.获取信息摘要对象:md5

      通过信息摘要单例的构造函数获取:

      MessageDigest md5 = MessageDigest.getInstance("MD5");
      
            
            
      • 1
      • 2
    • 2.信息摘要对象是对字节数组进行摘要的,所以先获取字符串的字节数组.

      byte[] bytes = str.getBytes();
      
            
            
      • 1
      • 2
    • 3.信息摘要对象对字节数组进行摘要,得到摘要字节数组:

      byte[] digest = md5.digest(bytes);
      
            
            
      • 1
      • 2
    • 4.把摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5值.
      (PS,有些转换过来得到的是前面有6个f的情况,如:ffffff82,这是因为前面有6组4个1,所以提前把这6组1111先变成0就好了,然后再转16进制就没有f了)
      (其实也可以在后面续把f去掉)


    2.加密文件

    方法传入的是文件对象 : file

    • 1.因为是文件不是方法,所以不是像刚才那样通过摘要获取字符串.

    • 2.使用到另一个方法即可:就是信息摘要对象更新:md5.update(byte[] input)方法,用法是通过读取流,不断的更新从流中读到的”信息数组”.

    • 3.然后通过”信息摘要对象”获取摘要,不用参数:md5.digest(),此时返回的数组就已经是包含内容的摘要数组


    以下是详细代码:

    public class MD5Tool {
        public static void main(String[] args) throws Exception {
            /*--------------字符串--------------*/
            String str = "12345";
            String md1 = getMD5(str);
            System.out.println(md1);//827ccb0eea8a706c4c34a16891f84e7b
    
            /*--------------文件--------------*/
            File file = new File("D:\\1.mp3");
            String md2 = getMD5(file);
            System.out.println(md2);//9068aaead9a5b75e6a54395d8183ec9
        }
        /**
         * 逻辑:
         *
         * 1.获取md5对象,通过"信息摘要"获取实例构造("MD5").
         * 2.md5对象对("字符串的"字节形式"-得到的数组)进行摘要",那么会返回一个"摘要的字节数组"
         * 3.摘要字节数组中的"每个二进制值"字节形式,"转成十六进制形式",然后再把这些值给拼接起来,就是MD5值了
         *      (PS:为了便于阅读,把多余的fff去掉,并且单个字符前加个0)
         *
         */
        public static String getMD5(String str) throws Exception {
    
            String MD5 = "";
    
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = str.getBytes();
            byte[] digest = md5.digest(bytes);
    
            for (int i = 0; i < digest.length; i++) {
                //摘要字节数组中各个字节的"十六进制"形式.
                int j = digest[i];
                 j = j & 0x000000ff;
                String s1 = Integer.toHexString(j);
    
                if (s1.length() == 1) {
                    s1 = "0" + s1;
                }
                MD5 += s1;
            }
            return MD5;
        }
        //重载,所以用户传入"字符串"或者"文件"都可以解决.
    
        /**
         * 处理逻辑:
         * 1.现在传入的是"文件",不是字符串
         * 2.所以信息摘要对象.进行摘要得到数组不能像上面获得:md5.digest(bytes),因为不是str.getBytes得到bytes
         * 3.其实还是通过mdt.digest();获取到字节数组,但是前期必须要有一个方法必须是md5.update(),即"信息摘要对象"要先更新
         * 4."信息摘要更新"里面有(byte[] input),说明是读取流获取到的数组,所以我们就用这个方法.
         * 5.所以最终的逻辑就是:
         *
         *      1.获取文件的读取流
         *      2.不停的读取流中的"内容"放入字符串,放一部分就"更新"一部分.直到全部完毕
         *      3.然后调用md5.digest();就会得到有内容的字节数组,剩下的就和上边一样了.
         */
        public static String getMD5(File file) throws Exception {
            String MD5 = "";
    
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            FileInputStream fis = new FileInputStream(file);
    
            byte[] bytes = new byte[1024 * 5];
    
            int len = -1;
            while ((len=fis.read(bytes))!=-1) {
                //一部分一部分更新
                md5.update(bytes, 0, len);
            }
            byte[] digest = md5.digest();
            for (int i = 0; i <digest.length; i++) {
                int n = digest[i] & 0x000000ff;
                String s = Integer.toHexString(n);
    
                MD5 += s;
            }
            return MD5;
        }
    }
        
        
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    拓展

    0xfffffff代表的含义:


    • 0x:代表16进制;

    • 一个f代表:4个1,即(1111);

    • 所以0xffffffff代表:8组4个1

    1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111 
    
    
        
        
    • 1
    • 2
  • 所以刚才的0xffffff82就是前面6组都是1,后面两组是

  • 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 0111 - 0010 
    
    
        
        
    • 1
    • 2
  • 所以先与上0x000000ff,即

0000 - 0000 - 0000 - 0000 - 0000 - 0000 - 1111 - 1111
  • 就得到了82了

上面的方法也可以写成:


   for (int i = 0; i < digest.length; i++) {
            //摘要字节数组中各个字节的"十六进制"形式.
            String s1 = Integer.toHexString( digest[i]);

            //如果是8个长度的,把前面的6个f去掉,只获取后面的
            if (s1.length() == 8) {
                s1 = s1.substring(6);
            }
            if (s1.length() == 1) {
                s1 = "0" + s1;
            }
            MD5 += s1;
        }

猜你喜欢

转载自blog.csdn.net/nwpu_geeker/article/details/79694992