tools / des
des/
DES 對稱式加密與解密,用來串接仍在使用 DES 的舊系統。模式、填補、金鑰與 IV 的格式、字元集都可以選,結果與 Java、CryptoJS 一致,金鑰不會離開瀏覽器。
明文
密文
歷史紀錄
每次加密、解密成功後會自動記錄一筆,保留最近 20 筆,只存在這台裝置的瀏覽器裡。不會儲存金鑰,但會儲存 IV 和解密出的明文,在公用電腦上用完請清除紀錄。
AES、DES、RSA 是什麼,有什麼差別
AES 和 DES 是對稱式加密:加密和解密用同一把金鑰,就像同一把鑰匙既能鎖門也能開門。它們速度快,適合加密大量資料,難處在於要怎麼把這把金鑰安全地交給對方。
DES 是 1970 年代的老標準,有效金鑰只有 56 位元,現在用專用硬體或電腦叢集就能暴力破解,只適合用來串接仍在使用它的舊系統。AES 是取代 DES 的新標準,金鑰長度為 128、192 或 256 位元,目前沒有可行的破解方法,是現在加密資料的首選。
RSA 是非對稱式加密:有一對金鑰,公鑰可以公開給任何人,用來加密;私鑰自己保管,用來解密。就像一個誰都能投信、只有你有鑰匙的信箱。好處是不用事先約定金鑰,缺點是很慢,一次只能加密幾百位元組。實際系統常把兩者結合:先用 RSA 加密一把隨機產生的 AES 金鑰傳給對方,再用 AES 加密真正的資料。
加密模式是什麼,該選哪個
DES 每次只能加密 8 位元組,模式決定一長串資料如何切成區塊、區塊之間如何關聯。ECB 每個區塊單獨加密,相同的內容會得到相同的密文,會暴露資料規律,不建議使用。CBC 讓每個區塊先與前一個區塊的密文混合再加密,第一個區塊則與 IV 混合,是最常見的選擇。CFB、OFB、CTR 把 DES 變成一串金鑰串流,與資料逐位元組做 XOR,可以不填補。
金鑰、IV 與填補
DES 的金鑰是 8 位元組,其中每個位元組的最低位是檢查位元、不參與運算,所以有效金鑰只有 56 位元。超過 8 位元組時只用前 8 位元組,與 Java 的 DESKeySpec、CryptoJS 相同;不足 8 位元組會顯示錯誤。除 ECB 外都需要 8 位元組的 IV,它不需要保密,但同一把金鑰下不要重複使用。
ECB 和 CBC 要求資料長度是 8 位元組的整數倍,不足時依填補方式補齊。PKCS5Padding 和 PKCS7Padding 對 DES 完全相同,也是最常用的;ZeroPadding 補 0,解密時會去掉結尾所有的 0 位元組,明文本身以 0 位元組結尾時也會一併被去掉;NoPadding 不補,長度要自己確保。
和 Java、CryptoJS 的寫法怎麼對應
Java 的 Cipher.getInstance("DES/CBC/PKCS5Padding") 就是選 CBC 和 PKCS5Padding;只寫 "DES" 時預設是 ECB 和 PKCS5Padding。Java 的 CTR 只能用 NoPadding。CryptoJS.DES.encrypt 的模式和填補名稱一一對應,CryptoJS.pad.Pkcs7 對應 PKCS7Padding。新系統請直接用 AES。
常見問題
這裡能加解密 3DES(DESede、TripleDES)嗎
不能,這裡只有單重 DES。3DES 的金鑰是 16 或 24 位元組,貼進來只會用前 8 位元組,算出的結果與 3DES 不同,金鑰欄旁也會提示「只用前 8 位元組」。需要 3DES 請改用支援 DESede 的工具。
提示「金鑰是 N 位元組,DES 金鑰至少要 8 位元組」怎麼辦
少於 8 位元組會顯示錯誤,這裡不會自動補零,需要自己補到 8 位元組。更容易踩雷的是格式選錯:16 個字元的 hex 金鑰如果金鑰格式選成 string,會被當成 16 位元組的文字,只用前 8 個字元,不會顯示錯誤,只會在金鑰欄旁和結果下方提示「只用前 8 位元組」,結果自然對不上。選 string 時位元組數依所選字元集計算,一個中文字在 UTF-8 下佔 3 位元組。
提示「IV 必須是 8 位元組」怎麼辦
DES 的 IV 要剛好 8 位元組,不是 AES 的 16 位元組,除 ECB 外的模式都是如此。金鑰超過 8 位元組會取前 8 位元組,IV 則不會,多了或少了都會直接顯示錯誤,所以從 AES 參數拿來的 16 位元組 IV 要改成 8 位元組。同樣要先看格式:16 個字元的 hex 才是 8 位元組,選 string 就是 16 位元組。ECB 不需要 IV,IV 欄會隱藏。
解密時提示「填補不正確」或「密文不是 8 的整數倍」怎麼辦
密文長度不是 8 的整數倍,多半是複製不完整,或是 hex 和 base64 選反了。填補不正確,通常是金鑰、IV、模式或填補方式有一項與加密時不一致。ZeroPadding 和 NoPadding 不檢查填補,不會出現這個錯誤,但參數不對時結果是亂碼。
解密結果開頭一段是亂碼,或提示「不是有效的 UTF-8 文字」
先查 IV。密文超過一個區塊時,CBC 和 CFB 模式下 IV 不對,只會讓第一個 8 位元組的區塊出錯,後面的內容正常,也不會出現填補錯誤,現象就是開頭亂碼、後面是對的。如果提示結果不是有效的文字,也可能是字元集與加密端不一致,例如對方用的是 GBK。把輸出格式改成 hex,可以先確認解出來的位元組本身對不對。
加密結果和 Java、CryptoJS 對不上,該怎麼找出原因
依這個順序核對:模式和填補、金鑰和 IV 的格式與位元組數、字元集、輸入輸出格式。string 格式的明文不會去掉頭尾空白,結尾多一個換行就是另一段資料。CTR、CFB、OFB 在這裡也會依所選填補補齊,選 PKCS5Padding 時密文比明文長,後端用 NoPadding 的話這裡也要選 NoPadding。CFB 是 64 位元整區塊回饋,對方用 CFB8 的話會對不上。
CryptoJS.DES.encrypt 的結果以 U2FsdGVkX1 開頭,這裡能解嗎
不能。CryptoJS.DES.encrypt(明文, 字串) 傳入字串時,會把它當作密碼短語:隨機加鹽,再依 OpenSSL 的方式推導出金鑰和 IV,結果以 U2FsdGVkX1 開頭,這裡不支援這種格式。要與這裡對上,請在 CryptoJS 裡用 CryptoJS.enc.Utf8.parse 把金鑰轉成位元組再傳入,並明確指定 iv、mode 和 padding。
歷史紀錄裡存了什麼,會上傳嗎
只存在這台裝置瀏覽器的 localStorage 裡,不會上傳,頁面程式碼裡沒有任何網路請求。每次成功加密或解密後記錄一筆,最多保留 20 筆,輸入或結果超過 2 萬字元的不記錄。紀錄裡有參數、IV、輸入和結果,以及一個由金鑰前 8 位元組算出的 8 位指紋(紀錄裡 # 號後面那串字元,用來分辨是不是同一把金鑰),不存金鑰本身,所以點「填入」後要重新填入金鑰。每筆都可以單獨刪除,在公用電腦上用完請點「清除紀錄」。