tools / des
des/
DES の共通鍵暗号化と復号。まだ DES を使う旧システムとの連携用です。モード、パディング、鍵と IV の形式、文字コードを選べ、結果は Java・CryptoJS と一致します。鍵はブラウザの外に出ません。
平文
暗号文
履歴
暗号化・復号に成功するたびに自動で記録し、最新 20 件をこの端末のブラウザだけに保存します。鍵は保存しませんが、IV と復号した平文は保存されるので、共用パソコンでは使い終わったら履歴を消去してください。
AES・DES・RSA とは? その違い
AES と DES は共通鍵暗号です。暗号化と復号に同じ鍵を使い、1 本の鍵でドアを閉めて開けるようなものです。高速で大量のデータに向いていますが、その鍵をどうやって安全に相手へ渡すかが課題になります。
DES は 1970 年代の古い標準で、実質的な鍵長は 56 ビットしかなく、今では専用ハードウェアやコンピューター群で総当たり解読できます。まだ DES を使う古いシステムとの連携専用です。AES は DES に代わる標準で、鍵は 128・192・256 ビット。現在、現実的な解読方法はなく、データ暗号化の第一候補です。
RSA は公開鍵暗号です。鍵はペアになっていて、公開鍵は誰に渡してもよく暗号化に使い、秘密鍵は自分だけが持って復号に使います。誰でも手紙を入れられて、自分だけが鍵で開けられる郵便受けのようなものです。事前に鍵を取り決める必要はありませんが、遅く、一度に数百バイトしか暗号化できません。実際のシステムでは両方を組み合わせ、ランダムに作った AES 鍵を RSA で暗号化して相手に送り、本体のデータは AES で暗号化するのが一般的です。
暗号モードとは? どれを選ぶか
DES は一度に 8 バイトしか暗号化できず、モードは長いデータをどうブロックに分け、ブロック同士をどうつなぐかを決めます。ECB は各ブロックを個別に暗号化するため、同じ内容は同じ暗号文になりデータの規則性が漏れるので非推奨です。CBC は各ブロックを直前の暗号文と混ぜてから暗号化し、最初のブロックは IV と混ぜます。最も一般的な選択です。CFB・OFB・CTR は DES を鍵ストリームに変えてデータと 1 バイトずつ XOR するので、パディングが不要です。
鍵・IV・パディング
DES の鍵は 8 バイトですが、各バイトの最下位ビットはパリティビットで演算に使われないため、実質的な鍵長は 56 ビットしかありません。8 バイトを超える鍵は先頭 8 バイトだけを使い、Java の DESKeySpec や CryptoJS と同じ動作です。8 バイト未満はエラーになります。ECB 以外のモードは 8 バイトの IV が必要です。秘密にする必要はありませんが、同じ鍵で使い回さないでください。
ECB と CBC はデータ長が 8 バイトの倍数である必要があり、足りない分はパディング方式に従って埋めます。DES では PKCS5Padding と PKCS7Padding はまったく同じで、最もよく使われます。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 バイト未満だとエラーになり、自動で 0 埋めはしないので、自分で 8 バイトにそろえてください。もっと起こりやすいのは形式の選択ミスです。16 文字の hex 鍵を、鍵の形式を string にして入力すると、16 バイトのテキストとして扱われ、先頭の 8 文字しか使われません。エラーにはならず、鍵の欄の横と結果の下に「先頭 8 バイトのみ使用」と表示されるだけで、結果は当然合いません。string 形式では選択した文字コードでバイト数が決まり、日本語や中国語の文字 1 文字は UTF-8 で 3 バイトです。
「IV は 8 バイトにしてください」と表示されたらどうしますか?
DES の IV はちょうど 8 バイトで、AES の 16 バイトではありません。ECB 以外のモードはすべて同じです。鍵は 8 バイトを超えると先頭の 8 バイトが使われますが、IV は切り詰められず、長くても短くてもエラーになるので、AES の設定から持ってきた 16 バイトの IV は 8 バイトに直してください。形式も確認してください。16 文字の hex なら 8 バイトですが、同じ 16 文字でも string 形式なら 16 バイトです。ECB では IV は不要で、IV の欄は非表示になります。
復号で「パディングが不正」「8 の倍数ではありません」と表示されたらどうしますか?
暗号文の長さが 8 の倍数でないのは、コピーが不完全か、hex と base64 を取り違えている場合がほとんどです。パディングが不正という場合は、鍵・IV・モード・パディングのどれかが暗号化時と違うのが普通です。ZeroPadding と NoPadding はパディングを検査しないためこのエラーは出ませんが、パラメータが違うと結果は文字化けになります。
復号結果の先頭だけ文字化けする、または「正しい UTF-8 テキストではありません」と表示される
まず IV を確認してください。暗号文が 1 ブロックより長い場合、CBC と CFB モードで IV が違うと、壊れるのは最初の 8 バイトのブロックだけで、後ろの内容は正常に復号され、パディングのエラーも出ないため、先頭だけが文字化けして後ろは正しい、という状態になります。結果が正しいテキストではないと表示される場合は、文字コードが暗号化側と違う可能性もあります。たとえば相手が GBK を使っている場合です。出力形式を hex にすると、まず復号されたバイト列そのものが正しいか確認できます。
Java や CryptoJS と結果が一致しません。どう調べればいいですか?
次の順に確認してください。モードとパディング、鍵と IV の形式およびバイト数、文字コード、入出力の形式です。string 形式の平文は前後の空白が取り除かれないため、末尾に改行が 1 つあるだけで別のデータになります。CTR・CFB・OFB でも、ここでは選んだパディングで埋められるので、PKCS5Padding を選ぶと暗号文が平文より長くなります。バックエンドが NoPadding なら、ここでも NoPadding を選んでください。ここでの CFB は 64 ビットのブロック単位のもので、相手が CFB8 を使っていると一致しません。
CryptoJS.DES.encrypt の結果が U2FsdGVkX1 で始まります。ここで復号できますか?
できません。CryptoJS.DES.encrypt(平文, 文字列) のように文字列を渡すと、CryptoJS はそれをパスフレーズとして扱い、ランダムなソルトを付けて OpenSSL と同じ方式で鍵と IV を導出します。結果は U2FsdGVkX1 で始まり、この形式にはここでは対応していません。ここと結果を合わせるには、CryptoJS 側で CryptoJS.enc.Utf8.parse を使って鍵をバイト列に変換して渡し、iv・mode・padding を明示的に指定してください。
履歴には何が保存されますか?アップロードされますか?
この端末のブラウザの localStorage にだけ保存され、アップロードはされません。ページのコードにも通信処理はありません。暗号化または復号に成功するたびに 1 件記録され、最大 20 件まで保持されます。入力か結果が 2 万文字を超えるものは記録されません。記録にはパラメータ・IV・入力・結果と、鍵の先頭 8 バイトから計算した 8 文字のフィンガープリント(各記録の # の後ろの文字列で、同じ鍵かどうかの判別に使います)が含まれますが、鍵そのものは保存されないため、「読み込む」を押したあとは鍵を入力し直す必要があります。1 件ずつ削除でき、共用パソコンでは使い終わったら「履歴を消去」を押してください。