最終更新:

暗号化の仕組み — メモを読めない形にして、鍵で戻す


メモを変えて、同じ鍵で戻す

平文のメモりんご鍵で暗号化暗号文 9バイト同じ鍵で復号✓ メモが「りんご」に戻る
本文のAES-GCMの実験です。復号にはnonceと認証タグも使います。9バイトは暗号文だけの長さです。
ひよこ ひよこ
大事なメモを、途中で読まれないようにするには?
ペンギン先生 ペンギン先生
暗号化は、鍵を使って平文を暗号文へ変えることだよ。復号すると元のメモへ戻る。下の実験では、同じ鍵を使うAES-GCMで「りんご」を変えて、読み戻してみよう。
ひよこ ひよこ
読めない形なら、文字を適当に混ぜればいい?
ペンギン先生 ペンギン先生
独自の混ぜ方ではなく、検証された方式とライブラリを使うんだ。Base64はデータの表し方で、秘密の鍵がなくても戻せる。暗号化とは違うよ。
ひよこ ひよこ
同じ鍵を使うのが、共通鍵暗号?
ペンギン先生 ペンギン先生
そう。送る側と受け取る側が秘密の鍵を共有する。鍵の保管や共有が大切なんだ。AES-GCMでは同じ鍵で使うnonceを重複させず、改ざん検出用のタグも一緒に扱うよ。
ひよこ ひよこ
公開鍵は、公開していいの?
ペンギン先生 ペンギン先生
公開鍵と秘密鍵を使う仕組みだよ。ただし、公開鍵が誰のものかの確認は必要だね。公開鍵暗号には暗号化、署名、鍵合意など異なる役割があり、同じ操作ではないんだ。
ひよこ ひよこ
HTTPSでは、共通鍵を公開鍵で送るの?
ペンギン先生 ペンギン先生
TLS 1.3の代表的な証明書を使う接続では、鍵合意から共有秘密を導き、通信用の鍵を作るよ。共通鍵をRSAで暗号化して送る古い説明を、そのまま当てはめない。事前共有鍵を使う接続もあるんだ。
ひよこ ひよこ
暗号化できたら、相手も本物だと分かる?
ペンギン先生 ペンギン先生
別の問いだね。TLSでは証明書等で相手を確認し、署名等も使って接続の内容を確かめる。暗号化だけでは、間違った相手にデータを渡すことを防げないよ。
ひよこ ひよこ
ハッシュも、鍵で元に戻すの?
ペンギン先生 ペンギン先生
ハッシュは入力から要約値を作るもので、復号の操作はないよ。でも、短いパスワードは候補を試して照合され得る。単純なSHA-256だけでなく、パスワード保存向けの方式とsalt等を使うんだ。
ひよこ ひよこ
量子コンピューターへの対策は、全部置き換える?
ペンギン先生 ペンギン先生
鍵合意や署名等、役割ごとに考えるよ。NISTのML-KEMは鍵を共有するための方式、ML-DSAは署名の方式。新しい名前を覚える前に、何を守る操作かを分けると理解しやすいね。

まずは、「りんご」を暗号化して読み戻す

Node.jsが使えるなら、次をencrypt-demo.cjsへ保存し、node encrypt-demo.cjsで試してみましょう。鍵は実行ごとに作る練習です。

const crypto = require("node:crypto");
const key = crypto.randomBytes(32);
const nonce = crypto.randomBytes(12);
const cipher = crypto.createCipheriv("aes-256-gcm", key, nonce);
const encrypted = Buffer.concat([
  cipher.update("りんご", "utf8"), cipher.final(),
]);
const tag = cipher.getAuthTag();
const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce);
decipher.setAuthTag(tag);
const restored = Buffer.concat([
  decipher.update(encrypted), decipher.final(),
]);
console.log("暗号文のバイト数:", encrypted.length);
console.log(restored.toString("utf8"));
暗号文のバイト数: 9
りんご

暗号文の値は毎回変わります。この9バイトはメモの暗号文だけで、nonce・タグ等を含む保存データ全体の大きさではありません。AES-GCMでは同じ鍵に対するnonceの重複を避け、受信側はタグを検証します。この短い練習から、鍵の永続保存・安全な配布まで実現できたとは考えません。

似て見える操作を分ける

操作何をするか
暗号化・復号鍵で読めない形にし、戻す
署名・検証秘密鍵で署名し、対応する公開鍵で確かめる
鍵合意やり取りから共有秘密を導く
ハッシュ入力の要約値を作る。復号はしない
Base64バイトを文字で表す。秘匿する操作ではない

公開鍵を受け取っただけでは、意図した相手の鍵とは分かりません。証明書や事前に確認した情報等で、鍵と相手を結び付けます。署名を「秘密鍵で暗号化するだけ」と覚えるのも避けましょう。

TLSとパスワード保存をもう少し詳しく

TLS 1.3では、通信データは認証付き暗号で保護します。代表的な証明書付き接続では(E)DHE等の鍵合意から秘密を導き、鍵導出で通信鍵を作ります。事前共有鍵の経路もあり、「公開鍵で共通鍵を送る」の一文ですべてを説明できません。TLS 1.3の仕様はRFC 9846で更新されています。

ハッシュ値しか保存しなくても、攻撃者がパスワード候補の値を計算して比較することは可能です。用途に合うパスワードハッシュ方式、salt、計算コスト、アクセス制御を組み合わせます。暗号化で復号できる保存とは目的が違います。

耐量子方式も役割が異なります。NISTのFIPS 203はML-KEM、FIPS 204はML-DSAを定めています。すべての既存暗号を同じ方式へ入れ替える、という意味ではありません。

🐧 ペンギン先生のまとめ:「暗号化」って出てきたら「鍵を使って読めない形にし、必要な相手だけが戻す仕組み」と思えばだいたいOK!

通信の接続はSSHの仕組み、Webの保護はHTTPSの仕組みへ進めます。

参考資料