關於 MD5 加密中 ByteToHex 使用位運算的意義
阿新 • • 發佈:2021-10-07
先上一段使用 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();
- 這裡有這樣一段程式碼:
(temp & 0x000000FF) | 0xFFFFFF00
, 根據運算子優先順序其實它等同於temp & 0x000000FF | 0xFFFFFF00
- 這段程式碼的意義就是 ByteToHex 的核心, 根據程式碼上下文可知 temp 是遍歷 md5.digest() 返回值的 byte 型別臨時變數, 其總長度為 16, 而下面的 for 迴圈就是將這個長度為 16 的 byte 陣列轉換為 hex 字串
- 轉換的規則為: 如果 byte 的值大於 15 則直接將其 16 進位制形式的文字追加到 hex 字串上, 否則先在 hex 字串上追加一個
0
再將 byte 的 16 進位制形式的文字追加到 hex 字串上(其實等同於temp/16
temp%16
兩位數字, 前提是temp 必須為正數
) - 上述轉換規則的原因是: 一個 byte 資料為 8 個二進位制位, 而一個 hex 資料(如: f)最大佔用 4 個二進位制位, 因此將一個 byte 資料對照為一個兩位 hex 資料, 不足兩位則在前面補
0
, 從而使得 MD5 的返回值為 32 位 - 程式碼
Integer.toHexString((temp & 0x000000FF) | 0xFFFFFF00).substring(6)
就是上述內容的具體實現
補充內容:
在以模為 256 的系統中, -13 == +243
, 我們稱 13
和 243
這兩個數在模為 256 的系統中互為補數, 如: 20 - 13 == 20 + 243 - 256 == 7
補數: 補數_百度百科
temp & 0x000000FF
的目的是將 temp 為負數的資料轉換為其對應符號為正的補數, 而 temp 為正的 byte 資料不受其影響(此時無論 temp 原本為正數還是負數, 其左側 24 位都為 0)- 再拿上一步的運算結果與
0xFFFFFF00
進行或運算
使得其 HexString 的長度一定為8
位(因為如果左側為 0 則會被省略, 導致 byte 對應 hex 的長度可能為 2 位(值大於等於 16), 也有可能為 1 位(值小於 16)。而0xFFFFFF00
保證了左側 24 位都為1
, 即: HexString 左側 6 位一定為FFFFFF
, 從而使得其 HexString 的長度一定為 8) - 最終再使用
substring(6)
將左側 6 位剪去, 這樣就保證了在 byte 值小於 16 的資料前面進行補0
操作。
其實可以將
Integer.toHexString((temp & 0x000000FF) | 0xFFFFFF00).substring(6)
寫為Integer.toHexString((temp & 0x000000FF) | 0xF00).substring(1)