JAVA加密系列(一)-Base64與單向加密算法MD5、SHA、HMAC

JAVA加密系列(一)-Base64與單向加密算法MD5、SHA、HMAC

Base64

Base64是網絡上最常見的用於傳輸8Bit字節碼的編碼方式之一,Base64就是一種基於64個可打印字符來表示二進制數據的方法,嚴格的來說base64屬於編碼格式並非加密算法,但是因爲base64是二進制數據可以和很多的加密算法配合產生化學反應,學加密前先了解清楚base64的原理,實質上應用場景非常廣泛,很容易掌握,不懂原理的可以看什麼是base64

單向加密

單向加密又稱爲不可逆加密算法,在加密過程中不使用密鑰,明文由系統加密處理成密文,密文無法解密。一般適合於驗證,在驗證過程中,重新輸入明文,並經過同樣的加密算法處理,得到相同的密文並被系統重新認證。廣泛使用於口令加密。

  • MD5(Message Digest algorithm 5,信息摘要算法)
  • SHA(Secure Hash Algorithm,安全散列算法)
  • HMAC(Hash Message Authentication Code,散列消息鑑別碼)

加密解析

Base64

  • 1 字節(byte) = 8 比特位(bit)
  • Base64 定義了 64 (2^6)個可打印字符表示二進制的方法,也就是說 6 個 bit 的二進制數據可以用對應的字符代替表示
  • 對於連續多個二進制數據,每 3 個字節一組進行轉換,3個字節 24 bit,然後將其分爲 4 部分(3×8 = 4×6),每個部分剛好 6 bit,將 6 bit 二進制轉換爲 Base64 定義的字符即完成轉換
  • 例, 6 bit 二進制是 000000,那麼對應的字符就是 A,如果 6 bit 二進制是 110011,那麼對應的字符就是 z
  • 若二進制數據字節數不是 3 的倍數,Base64 就將剩下的二進制數據補 0 至 3 的倍數,全 0 的用字符 “=” 代替

源碼解析

public static void main(String[] args) {
        //字符串編碼
        System.out.println("編碼結果:"+encrypt("hello word"));
        //字符串解碼
        System.out.println("編碼結果:"+decrypt("aGVsbG8gd29yZA=="));
    }

    public static String encrypt(String str){
        byte[] bytes=str.getBytes();
        bytes=Base64.getEncoder().encode(bytes);
        return new String(bytes);
    }

    public static String decrypt(String str){
        byte[] bytes=str.getBytes();
        bytes=Base64.getDecoder().decode(bytes);
        return new String(bytes);
    }
    
    log
    編碼結果:aGVsbG8gd29yZA==
    編碼結果:hello word

MD5

  • 一般用於確保信息的傳輸完整一致性,校驗傳輸的數據是否被修改,一旦原始信息被修改,生成的 MD5 值將會變得很不同
  • 算法能將任意大小、格式的文字或文件進行加密從而產生 128 bit(16 字節)的散列值。如同人的指紋,不同文本的 MD5 值是不同的。
  • 極端情況:就是不同的字符串的 MD5 值一樣,這叫哈希碰撞。2009 年中科院就已經實現了相應的碰撞算法,不過 MD5 應用仍然很廣泛
  • 一般不可破解,除非使用窮舉法,難度依舊很大
  • MD5加密算法,是一種被廣泛使用的密碼散列函數,可以產生出一個128位的散列值,用於確保信息傳輸完全一致,在很多方面都有着廣泛的應用,例如保存用戶密碼,比較下載文件的md5值以保證文件無損毀等等。

源碼解析

public static void main(String[] args) {
        //字符串編碼
        System.out.println("編碼結果:"+encryptMD5("hello word"));

    }

    public static String encryptMD5(String str){
        try {
            byte[] bytes=str.getBytes();
            MessageDigest messageDigest=MessageDigest.getInstance("MD5");
            messageDigest.update(bytes);
            bytes = messageDigest.digest();

            // digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
            // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
            //一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
            return new BigInteger(1, bytes).toString(16);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    log 
    編碼結果:13574ef0d58b50fab38ec841efe39df4

SHA

  • 在使用上跟MD5沒什麼差別,畢竟都是單向加密,祖宗都是MD4,下面列舉一下幾點不同點
  • 對強行攻擊的安全性:最顯著和最重要的區別是SHA-1摘要比MD5摘要長32 位。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對MD5是2128數量級的操作,而對SHA-1則是2160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。
  • 對密碼分析的安全性:由於MD5的設計,易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
  • 速度:在相同的硬件上,SHA-1的運行速度比MD5慢。
  • SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512這幾種單向散列算法。SHA-1,SHA-224和SHA-256適用於長度不超過264二進制位的消息。SHA-384和SHA-512適用於長度不超過2128二進制位的消息。

源碼解析

public static void main(String[] args) {
        //字符串編碼
        System.out.println("編碼結果:"+encrypt("hello word"));

    }

    public static String encrypt(String str){
        try {
            byte[] bytes=str.getBytes();
            MessageDigest messageDigest=MessageDigest.getInstance("SHA");
            messageDigest.update(bytes);
            bytes = messageDigest.digest();

            // digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
            // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
            //一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
            return new BigInteger(1, bytes).toString(16);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    log
    編碼結果:e0738b87e67bbfc9c5b77556665064446430e81c

HMAC

  • “散列消息鑑別碼”,主要是利用哈希算法,以一個密鑰和一個消息爲輸入,生成一個消息摘要作爲輸出。
  • 驗證TPM接受的授權數據和認證數據;
  • 確認TPM接受到的命令請求是已授權的請求,並且,命令在傳送的過程中沒有被改動過。
  • 定義HMAC需要一個加密用散列函數(表示爲H,可以是MD5或者SHA-1)和一個密鑰K。我們用B來表示數據塊的字節數。(以上所提到的散列函數的分割數據塊字長B=64),用L來表示散列函數的輸出數據字節數(MD5中L=16,SHA-1中L=20)。鑑別密鑰的長度可以是小於等於數據塊字長的任何正整數值。應用程序中使用的密鑰長度若是比B大,則首先用使用散列函數H作用於它,然後用H輸出的L長度字符串作爲在HMAC中實際使用的密鑰。一般情況下,推薦的最小密鑰K長度是L個字節。
  • 使用的密鑰是雙方事先約定的,第三方不可能知道。作爲非法截獲信息的第三方,能夠得到的信息只有作爲“挑戰”的隨機數和作爲“響應”的HMAC結果,無法根據這兩個數據推算出密鑰。由於不知道密鑰,所以無法仿造出一致的響應。
public static void main(String[] args) {
        //字符串編碼
        System.out.println("編碼結果:"+encrypt("hello word"));

    }

    public static String encrypt(String str){
        try {
            byte[] bytes=str.getBytes();
            SecretKey secretKey=new SecretKeySpec(bytes,"HmacMD5");
            Mac mac=Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes=mac.doFinal(bytes);
            // digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
            // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
            //一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
            return new BigInteger(1, bytes).toString(16);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    log 
    編碼結果:4b003eb6cb233122bb5a94ff468b95b7
    

源碼下載

GitHub,感興趣的點個星星

詳情文章

總結

單向加密應用非常廣泛,比較常用的用途是校驗數據或者文件在傳輸過程中是否修改,以上例子均展示的最簡單的實例,因爲都是基於byte數據進行操作,那麼完全可以使用base64以及位運算進行操作加大安全性,具體實現方式請查看後續文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章