1. 程式人生 > 其它 >關於 MD5 加密中 ByteToHex 使用位運算的意義

關於 MD5 加密中 ByteToHex 使用位運算的意義

先上一段使用 MD5 加密的程式碼

MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytesArr1 = txt.getBytes(StandardCharsets.UTF_8);
byte[] bytesArr2 = md5.digest(bytesArr1);
StringBuilder encrypt = new StringBuilder("");
for (byte temp : bytesArr2) {
    encrypt.append(Integer.toHexString((temp & 0x000000FF) | 0xFFFFFF00).substring(6));
}
return encrypt.toString();
  1. 這裡有這樣一段程式碼: (temp & 0x000000FF) | 0xFFFFFF00, 根據運算子優先順序其實它等同於 temp & 0x000000FF | 0xFFFFFF00
  2. 這段程式碼的意義就是 ByteToHex 的核心, 根據程式碼上下文可知 temp 是遍歷 md5.digest() 返回值的 byte 型別臨時變數, 其總長度為 16, 而下面的 for 迴圈就是將這個長度為 16 的 byte 陣列轉換為 hex 字串
  3. 轉換的規則為: 如果 byte 的值大於 15 則直接將其 16 進位制形式的文字追加到 hex 字串上, 否則先在 hex 字串上追加一個 0 再將 byte 的 16 進位制形式的文字追加到 hex 字串上(其實等同於 temp/16
    , temp%16 兩位數字, 前提是 temp 必須為正數)
  4. 上述轉換規則的原因是: 一個 byte 資料為 8 個二進位制位, 而一個 hex 資料(如: f)最大佔用 4 個二進位制位, 因此將一個 byte 資料對照為一個兩位 hex 資料, 不足兩位則在前面補 0, 從而使得 MD5 的返回值為 32 位
  5. 程式碼 Integer.toHexString((temp & 0x000000FF) | 0xFFFFFF00).substring(6) 就是上述內容的具體實現

補充內容:
在以模為 256 的系統中, -13 == +243, 我們稱 13243 這兩個數在模為 256 的系統中互為補數, 如: 20 - 13 == 20 + 243 - 256 == 7

補數: 補數_百度百科

  1. temp & 0x000000FF 的目的是將 temp 為負數的資料轉換為其對應符號為正的補數, 而 temp 為正的 byte 資料不受其影響(此時無論 temp 原本為正數還是負數, 其左側 24 位都為 0)
  2. 再拿上一步的運算結果與 0xFFFFFF00 進行 或運算 使得其 HexString 的長度一定為 8 位(因為如果左側為 0 則會被省略, 導致 byte 對應 hex 的長度可能為 2 位(值大於等於 16), 也有可能為 1 位(值小於 16)。而 0xFFFFFF00 保證了左側 24 位都為 1, 即: HexString 左側 6 位一定為 FFFFFF, 從而使得其 HexString 的長度一定為 8)
  3. 最終再使用 substring(6) 將左側 6 位剪去, 這樣就保證了在 byte 值小於 16 的資料前面進行補 0 操作。

其實可以將 Integer.toHexString((temp & 0x000000FF) | 0xFFFFFF00).substring(6) 寫為 Integer.toHexString((temp & 0x000000FF) | 0xF00).substring(1)