暗号化の仕組み — メモを読めない形にして、鍵で戻す
メモを変えて、同じ鍵で戻す
まずは、「りんご」を暗号化して読み戻す
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の仕組みへ進めます。
参考資料
- Node.js:crypto — AES-GCM・nonce・認証タグ・randomBytes
- IETF:RFC 9846 — TLS 1.3の認証付き暗号と鍵合意・PSK
- OWASP:Password Storage Cheat Sheet — パスワード向けのハッシュ・salt・計算コスト
- NIST:FIPS 203 — ML-KEMの鍵カプセル化
- NIST:FIPS 204 — ML-DSAの署名