🎄 科学と神々株式会社アドベントカレンダー 2025
License System Day 5: 暗号化の基礎 - 対称鍵と非対称鍵
📖 今日のテーマ
今日からセキュリティ基礎編に突入です!
ライセンス認証システムの心臓部である暗号化技術を学んでいきます。まずは基礎となる「対称鍵暗号」と「非対称鍵暗号」の違いを理解しましょう。
🔐 暗号化とは何か?
定義
暗号化(Encryption): データを第三者が読めない形に変換すること
元のデータ(平文):
"Hello, World!"
暗号化後(暗号文):
"4d8f2a9b7c3e1f6d..."
復号化:
"Hello, World!"
なぜ暗号化が必要か?
シナリオ: ライセンスキーの送信
暗号化なし:
クライアント → "license-key-12345" → サーバー
↑
盗聴者が見える!
→ 不正利用される
暗号化あり:
クライアント → "a8f3d2e1..." → サーバー
↑
盗聴者には意味不明
→ 安全!
🔑 対称鍵暗号(Symmetric Encryption)
仕組み
同じ鍵で暗号化と復号化を行う
┌──────────┐ ┌──────────┐
│ 送信者 │ │ 受信者 │
└────┬─────┘ └────┬─────┘
│ │
│ 共通鍵: "secret123" │ 共通鍵: "secret123"
│ │
├─ 1. 暗号化 ─────────────────┤
│ "Hello" + "secret123" │
│ ↓ │
│ "4d8f2a9b..." │
│ │
├──── 2. 送信 ───────────────►│
│ │
│ ├─ 3. 復号化
│ │ "4d8f2a9b..." + "secret123"
│ │ ↓
│ │ "Hello"
代表的なアルゴリズム
AES (Advanced Encryption Standard)
// Node.js での実装例
const crypto = require('crypto');
// 暗号化
function encrypt(text, key) {
const cipher = crypto.createCipher('aes-256-cbc', key);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
// 復号化
function decrypt(encrypted, key) {
const decipher = crypto.createDecipher('aes-256-cbc', key);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// 使用例
const key = 'my-secret-key-32-characters-long!!';
const text = 'Hello, World!';
const encrypted = encrypt(text, key);
console.log('暗号化:', encrypted);
// → a3f8d2e1b4c7...
const decrypted = decrypt(encrypted, key);
console.log('復号化:', decrypted);
// → Hello, World!
メリット・デメリット
✅ メリット:
- 高速(CPUに負荷が少ない)
- 大量のデータに適している
- 実装がシンプル
❌ デメリット:
- 鍵の共有が難しい
- 鍵が漏れたら全て終わり
- 多人数での使用に不向き
鍵の共有問題
問題: どうやって鍵を安全に共有する?
シナリオ1:
メールで送る → メールが盗聴されたら終わり
シナリオ2:
電話で伝える → 聞き間違いの可能性
シナリオ3:
対面で渡す → 現実的ではない
→ 対称鍵暗号だけでは不十分!
🔐 非対称鍵暗号(Asymmetric Encryption)
仕組み
2つの鍵を使う: 公開鍵と秘密鍵
┌──────────────────────────────────────────────┐
│ 送信者(Alice) │
├──────────────────────────────────────────────┤
│ 公開鍵(Bob's Public Key)を入手 │
│ ↓ │
│ メッセージを公開鍵で暗号化 │
│ "Hello" + Bob's Public Key │
│ → "x7f2d9a3..." │
│ │
│ 暗号文を送信 ──────────────────────────┐ │
└──────────────────────────────────────────┼────┘
│
▼
┌──────────────────────────────────────────┴────┐
│ 受信者(Bob) │
├───────────────────────────────────────────────┤
│ 秘密鍵(Bob's Private Key)で復号化 │
│ "x7f2d9a3..." + Bob's Private Key │
│ → "Hello" │
│ │
│ ✅ 成功! │
└───────────────────────────────────────────────┘
ポイント:
公開鍵で暗号化 → 秘密鍵でしか復号化できない
秘密鍵は Bob だけが持っている → 安全!
鍵のペア
公開鍵(Public Key):
- 誰にでも公開してOK
- GitHubに載せてもOK
- メールで送ってもOK
- 暗号化に使用
秘密鍵(Private Key):
- 絶対に秘密
- 漏れたら全て終わり
- 復号化に使用
- 署名作成に使用
代表的なアルゴリズム
RSA
const crypto = require('crypto');
// 鍵ペアの生成
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
// 暗号化(公開鍵で)
function encryptRSA(text, publicKey) {
return crypto.publicEncrypt(
publicKey,
Buffer.from(text, 'utf8')
).toString('base64');
}
// 復号化(秘密鍵で)
function decryptRSA(encrypted, privateKey) {
return crypto.privateDecrypt(
privateKey,
Buffer.from(encrypted, 'base64')
).toString('utf8');
}
// 使用例
const text = 'Secret Message';
const encrypted = encryptRSA(text, publicKey);
console.log('暗号化:', encrypted);
const decrypted = decryptRSA(encrypted, privateKey);
console.log('復号化:', decrypted);
// → Secret Message
ECDSA (Elliptic Curve DSA)
// 鍵ペアの生成(楕円曲線)
const { publicKey, privateKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'prime256v1', // P-256
});
// このシステムで使用!
// RSA より高速で鍵サイズが小さい
メリット・デメリット
✅ メリット:
- 鍵の共有が不要
- 公開鍵は誰に渡してもOK
- デジタル署名が可能
❌ デメリット:
- 遅い(対称鍵の100〜1000倍遅い)
- 大量のデータには不向き
- 実装が複雑
🔄 ハイブリッド暗号化
両方の良いとこ取り
実際のシステムでは対称鍵 + 非対称鍵を組み合わせる
手順:
1. ランダムな対称鍵を生成
AES鍵: "random-key-xyz123"
2. この対称鍵でデータを暗号化(高速!)
"大量のデータ..." + AES鍵
→ "暗号化データ..."
3. 対称鍵を公開鍵で暗号化(小さいので問題なし)
"random-key-xyz123" + 公開鍵
→ "暗号化された鍵..."
4. 両方を送信
{
encryptedData: "暗号化データ...",
encryptedKey: "暗号化された鍵..."
}
5. 受信者は秘密鍵で対称鍵を復号
"暗号化された鍵..." + 秘密鍵
→ "random-key-xyz123"
6. 対称鍵でデータを復号
"暗号化データ..." + "random-key-xyz123"
→ "大量のデータ..."
→ 速度とセキュリティを両立!
実世界の例: HTTPS
HTTPS の通信:
1. ハンドシェイク(非対称鍵)
クライアント ←→ サーバー
TLS証明書の検証
セッション鍵を安全に共有
2. データ転送(対称鍵)
セッション鍵で高速に暗号化
大量のデータを効率的に送受信
3. 終了
セッション鍵を破棄
📊 比較表
| 項目 | 対称鍵暗号 | 非対称鍵暗号 |
|---|---|---|
| 鍵の数 | 1つ | 2つ(公開鍵 + 秘密鍵) |
| 速度 | 高速 | 低速 |
| 鍵の共有 | 困難 | 容易 |
| 用途 | 大量データ | 鍵交換・署名 |
| アルゴリズム | AES, DES | RSA, ECDSA |
| 鍵サイズ | 128-256 bit | 2048-4096 bit (RSA) 256 bit (ECDSA) |
🎯 ライセンスシステムでの使い方
このシステムでは非対称鍵を使用
理由:
✅ 鍵の共有が不要
公開鍵をクライアントに配布するだけ
✅ デジタル署名が可能
サーバーからのレスポンスが本物か検証
✅ クライアント側で検証可能
オフラインでも署名検証できる
具体的な用途:
1. ライセンスキー(JWT)の署名
2. API レスポンスの署名
3. 改ざん防止
フロー
サーバー側:
1. 秘密鍵で署名を生成
2. データ + 署名を送信
クライアント側:
3. 公開鍵で署名を検証
4. 検証OK → データを信頼
検証NG → エラー(改ざんされている)
🌟 まとめ
今日学んだこと:
-
暗号化の基本
- 平文 → 暗号文 → 平文
-
対称鍵暗号
- 同じ鍵で暗号化・復号化
- 高速だが鍵の共有が困難
-
非対称鍵暗号
- 公開鍵と秘密鍵のペア
- 鍵の共有が不要
- デジタル署名が可能
-
ハイブリッド暗号化
- 両方の良いとこ取り
- 実世界ではこれを使う
-
ライセンスシステムでの使用
- ECDSA で署名生成・検証
🎓 理解度チェック
- 対称鍵暗号と非対称鍵暗号の違いは?
- なぜ公開鍵は公開してもOK?
- ハイブリッド暗号化の利点は?
- HTTPS ではどのように使われている?
💡 次回予告
Day 6: ECDSA P-256署名の仕組み
- 楕円曲線暗号とは
- なぜ ECDSA を選ぶのか
- P-256 カーブの特徴
- RSA との違い
- 実際のコード例
お楽しみに!
前回: Day 4: 商用グレードのアーキテクチャ設計パターン
次回: Day 6: ECDSA P-256署名の仕組み
Happy Learning! 🎉