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;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章