在 Python 中,將十六進位轉成 Base64 是一個只需兩行程式碼的標準函式庫操作:bytes.fromhex() 會將連續的十六進位字串解析為原始位元組,而 base64.b64encode() 則會回傳符合 RFC 4648 規範的填充式 Base64 表示法。其結果是一個 bytes 字面值,這也代表幾乎每個正確腳本的第三行都會呼叫 .decode("ascii")。不論輸入來自雜湊值、網路封包、十六進位傾印,或是 Cryptopals 練習題,轉換路徑都完全相同:驗證十六進位字串的字元數為偶數,且字元僅來自 0-9 與 a-f 集合,將位元組交給 Base64 編碼器,然後複製印出的文字。這個模式之所以如此簡短,是因為兩個函式各自只做一件事。bytes.fromhex() 會拒絕奇數長度的輸入、非十六進位字元,以及 C 與 Rust 允許的 0x 前綴。base64.b64encode() 在位元組數量不是三的倍數時,總會用一個或兩個等號對輸出進行填充,這正是所有 RFC 4648 解析器都接受的標準形式。整個轉換過程是可逆且無資訊損失的,因此沒有任何需要設定的選項、沒有需要管理的金鑰,也沒有需要解讀的完整性檢查。

為了驗證這個模式能處理任意長度,知名的 Cryptopals Set 1 測試向量 "I'm killing your brain like a poisonous mushroom" 以 48 位元組的十六進位字串 49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d 表示時,經由完全相同的呼叫後會變成 SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t。在六位元組的煙霧測試與 48 位元組的句子之間,唯一會隨之改變的是取得位元組的方式;編碼邏輯本身並不會改變。

how to convert hex to base64 in python
how to convert hex to base64 in python

用兩行 Python 將十六進位轉成 Base64

Python 標準函式庫正好為這個轉換提供了兩個函式,兩者能夠協作,是因為 bytes.fromhex() 會回傳一個 bytes 物件,而 base64.b64encode() 預期接收的是 bytes-like 的輸入。輸出同樣也是一個 bytes 物件——這是多數程式碼片段在沒有解碼就直接列印時所忽略的部分。

以下是完整模式,使用 RFC 4648 的 "foobar" 測試向量,讓結果可以被獨立驗證:

import base64

hex_string = "666f6f626172"

raw = bytes.fromhex(hex_string)

b64 = base64.b64encode(raw).decode("ascii")

print(b64) # Zm9vYmFy

以下是相同邏輯拆解成的有序步驟,你可以根據任何輸入進行調整:

  1. 匯入 base64 模組,並將你的十六進位內容放入一個字元數為偶數的字串變數中。
  2. 呼叫 bytes.fromhex(hex_string) 來驗證輸入並產生原始位元組;當長度為奇數、出現 0x 前綴、底線或非十六進位字元時,該呼叫會引發 ValueError
  3. 將這些位元組傳給 base64.b64encode(raw),以取得包含 Base64 文字的 bytes 物件;若輸入長度不是三的倍數,則會以一個或兩個等號進行填充。
  4. 對結果呼叫 .decode("ascii"),如此才能將其列印、以文字模式寫入檔案,或貼到日誌行中。
  5. 將印出的字串與已知短輸入的預期輸出進行比對(位元組 b'foobar' 必須產生 Zm9vYmFy),以確認你的環境正在產生符合 RFC 4648 規範的標準 Base64。

三個小細節會決定這個程式印出的是正確字串還是令人困惑的字串。十六進位格式必須嚴格符合每個位元組兩個數字。解碼步驟正是將 b'Zm9vYmFy' 轉成可列印字串 "Zm9vYmFy" 的關鍵;若沒有這一步,print(b64) 仍可正常運作,但將 b64 直接寫入文字模式檔案會引發 TypeError。而 base64.b64encode() 總是產生標準的填充式 Base64,這也是大多數規格所要求的——若下游工具預期的是 base64url 或未填充的 Base64,你必須在事後另行轉換。

「嚴格十六進位」真正的含義

十六進位讓人覺得似乎很寬鬆,原因是任何單一的十六進位數字都是有效的——但一個位元組需要兩個數字。bytes.fromhex() 透過在位數為奇數、出現 0-9 與 a-f 以外的字元、以及其他語言允許的 0x 前綴時引發 ValueError,來強制這個界線。像是 "f" 這種單獨的值是不完整的,會被拒絕;"0f" 則是一個位元組。這正是防止輸入錯誤默默以零填充、進而產生錯誤位元組的機制。在多數規格所假設的嚴格 Base16 檢視中,十六進位輸出預設也是小寫:binascii.hexlify() 回傳小寫,bytes.hex() 也回傳小寫。若規格要求大寫十六進位,你可以在結果上呼叫 .upper()——但你不應該預設接收端工具會同時接受兩種大小寫,而不先加以確認。

格式範例bytes.fromhex() 的行為
純十六進位,偶數長度666f6f626172接受;回傳六個位元組 (b'foobar')
大寫十六進位數字666F6F626172接受;同樣是六個位元組
每個位元組加上 0x 前綴0x66 0x6f 0x6f 0x62 0x61 0x72拒絕;引發 ValueError
位數為奇數666f6f62617拒絕;引發 ValueError
含有空白或分隔符號66 6f 6f 62 61 72拒絕;引發 ValueError
位元組之間有底線66_6f_6f_62_61_72拒絕;引發 ValueError

這種嚴格性是一項特性,而非阻力。當你在比對雜湊值、代符或簽章時,這個界線檢查是唯一能在缺少數字導致下游錯誤比對發生之前就將其攔下的機制。

不想執行 Python 時的瀏覽器替代方案

對於臨時性的轉換——例如檢查日誌行中的承載資料、查看雜湊值背後的位元組,或是將某個值貼到工單中——開啟 REPL 或 Notebook 對這個任務來說太過厚重。Base64 to Hex Converter 能在你的瀏覽器中執行完全相同的 RFC 4648 Base64 與十六進位互轉作業,無需上傳,也無需管理 Python 執行環境。轉換契約與 Python 中 bytes.fromhex()b64encode() 所實作的相同:嚴格的字元驗證、精確的兩位數位元組、以及標準的填充式輸出。

選擇方向、貼上一種表示法、執行轉換,然後複製精確的結果。輸入上限為 500,000 個解碼後的位元組,以避免頁面在處理本該留在命令列的 gigabyte 級資料時陷入停滯。這個頁面也很適合作為交叉驗證之用。若你的 Python 輸出與轉換器印出的結果不一致,通常是以下兩種情況之一:輸入含有 bytes.fromhex() 在某個上游環節拒絕的 0x 前綴或空白字元,或是接收端工具實際上預期的是 base64url 或 MIME 包裝的 Base64,而非標準的 RFC 4648。這兩種情況在冗長的處理流程中都容易被忽略。關於反向轉換及其特殊陷阱,詳細的 Base64 轉十六進位指南 以相反的順序涵蓋了同樣的嚴格字母表與填充規則。

轉換作業悄悄出錯的環節

十六進位轉 Base64 的作業幾乎總是會成功;真正的危險在於以錯誤的位元組「成功」完成。大多數沉默的錯誤都來自以下幾種模式。

  • 先將十六進位字串進行 ASCII 解碼。 撰寫 "foobar".encode().hex() 是沒問題的,但 bytes.fromhex(hex_str.encode("ascii")) 多了一個你不需要的步驟。若該十六進位字串來自並非純 ASCII 的 socket 或檔案,這個額外的解碼可能會在邊界處損壞字元。
  • 呼叫了 b64decode 而非 b64encode。 這兩個名稱很容易搞混。b64decode 預期接收的是 Base64 輸入,若傳入十六進位會以 binascii.Error 失敗。它預設也是嚴格的——傳入 validate=False 會讓格式錯誤的輸入通過,並產生未定義的行為。
  • 混用 Base64 變體。 base64.urlsafe_b64encode() 會將 + 替換為 -、將 / 替換為 _,這在 URL 與許多 JWT 函式庫中是正確的,但對幾乎所有其他情境來說都是錯誤的。RFC 4648 標準 Base64 是安全的預設值;若協定規格中明確寫出「Base64url」或「URL-safe Base64」,才應刻意使用該函式。
  • 在短輸入上去除填充。 Python 的 b64encode 在輸入長度不是三的倍數時,總會在最後一組輸出 = 或 ==。若你為了配合固定寬度欄位而修剪了填充,下一個解碼器可能會拒絕該結果,除非被告知要寬鬆處理。
  • 以 UTF-8 而非位元組方式讀取輸入。 整個轉換的重點在於位元組的保真度。若你將十六進位傾印以 UTF-8 讀取,可能會將無效的位元組序列替換為 U+FFFD 取代字元,卻渾然不覺。

十六進位與 Base64 並非加密

十六進位與 Base64 都是相同位元組的可逆表示法——其中沒有金鑰、沒有擾亂、也沒有完整性檢查。base64.b64encode() 的輸出與你傳入的位元組一樣敏感。在將密碼雜湊、API 代符、私鑰或工作階段識別碼轉成 Base64 後再貼到聊天視窗中,並不會提供任何保護;它只是讓該值看起來較不具識別性。反向操作也是如此,這也是為什麼秘密的十六進位傾印仍然等同於秘密本身。

若你正在轉換的值涉及正式環境的憑證或簽章材料,請將轉換作業保留在本機執行。請在你自己的直譯器中執行 Python,而不是在會記錄輸入的代管 Notebook 中。只有在資料安全到足以放進瀏覽器分頁時,才使用基於瀏覽器的轉換器,並假設任何複製到剪貼簿的內容都可能會被同一頁面或在鍵盤前的另一位使用者讀取。對於任何需要保持機密的內容,答案就是使用真正的金鑰進行加密——而那是完全不同類別的工具,並非相同位元組的另一種編碼方式。

若你正在權衡各種選項,如何逐步手動將十六進位轉換為 Base64 對此有詳細的說明。