暗号化とは
暗号化は、データを第三者が読めない形式に変換する技術です。正しい鍵を持つ者だけが元のデータを復元(復号)できます。
なぜ必要か: 通信の盗聴、データベースへの不正アクセス、端末の紛失など、データが第三者の手に渡るリスクに対処するためです。
暗号化の種類
flowchart LR
subgraph Crypto["暗号化技術"]
subgraph Symmetric["共通鍵暗号(対称暗号)"]
S1["同じ鍵で暗号化/復号"]
end
subgraph Asymmetric["公開鍵暗号(非対称暗号)"]
A1["異なる鍵で暗号化/復号"]
end
subgraph Hash["ハッシュ関数(一方向関数)"]
H1["復号不可能、検証のみ"]
end
end
共通鍵暗号(対称暗号)
暗号化と復号に同じ鍵を使用します。
flowchart LR
P1["平文"] --> E["暗号化"]
K1["共通鍵"] --> E
E --> C["暗号文"]
C --> D["復号"]
K2["共通鍵(同じ)"] --> D
D --> P2["平文"]
代表的なアルゴリズム
| アルゴリズム | 鍵長 | 特徴 |
|---|---|---|
| AES | 128/192/256ビット | 現在の標準、高速 |
| ChaCha20 | 256ビット | モバイル向け、高速 |
| 3DES | 168ビット | レガシー、非推奨 |
実装例
const crypto = require('crypto');
// 暗号化
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
iv: iv.toString('hex'),
encrypted,
authTag: authTag.toString('hex')
};
}
// 復号
function decrypt(encryptedData, key) {
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
メリット・デメリット
| メリット | デメリット |
|---|---|
| 高速 | 鍵の配送が課題 |
| 大量データの暗号化に適する | 通信相手ごとに鍵が必要 |
公開鍵暗号(非対称暗号)
暗号化と復号に異なる鍵(公開鍵と秘密鍵)を使用します。
sequenceDiagram
participant S as 送信者
participant R as 受信者
Note over R: 秘密鍵(受信者のみ保持)<br/>公開鍵(公開)
R->>S: 公開鍵を送信
S->>S: 平文を公開鍵で暗号化
S->>R: 暗号文を送信
R->>R: 秘密鍵で復号 → 平文
代表的なアルゴリズム
| アルゴリズム | 用途 | 特徴 |
|---|---|---|
| RSA | 暗号化、署名 | 広く普及 |
| ECDSA | 署名 | 短い鍵で高セキュリティ |
| Ed25519 | 署名 | 高速、モダン |
| X25519 | 鍵交換 | 楕円曲線Diffie-Hellman |
デジタル署名
秘密鍵で署名し、公開鍵で検証します。
sequenceDiagram
participant S as 送信者(署名)
participant R as 受信者(検証)
S->>S: データを秘密鍵で署名
S->>R: データ + 署名を送信
R->>R: 公開鍵で検証 → 本物/偽物
メリット・デメリット
| メリット | デメリット |
|---|---|
| 鍵の配送が安全 | 共通鍵暗号より遅い |
| 認証、署名に使える | 大量データには不向き |
ハイブリッド暗号
実際のシステムでは、両者を組み合わせて使います。
sequenceDiagram
participant S as 送信者
participant R as 受信者
S->>S: 1. ランダムな共通鍵を生成
S->>S: 2. 共通鍵でデータを暗号化(高速)
S->>S: 3. 共通鍵を受信者の公開鍵で暗号化
S->>R: 4. 暗号化データ + 暗号化された共通鍵を送信
R->>R: 5. 秘密鍵で共通鍵を復号
R->>R: 6. 共通鍵でデータを復号
ハッシュ関数
任意の長さのデータから固定長のハッシュ値を生成します。元のデータを復元することはできません。
flowchart LR
A["'Hello'"] --> H1["SHA-256"] --> R1["185f8db32271fe25..."]
B["'Hello!'"] --> H2["SHA-256"] --> R2["334d016f755cd6dc..."]
Note["1文字変わるだけで<br/>全く異なるハッシュ値"]
代表的なアルゴリズム
| アルゴリズム | 出力長 | 用途 |
|---|---|---|
| SHA-256 | 256ビット | 一般的なハッシュ |
| SHA-3 | 可変 | 次世代標準 |
| bcrypt | 可変 | パスワードハッシュ |
| Argon2 | 可変 | パスワードハッシュ(推奨) |
パスワードのハッシュ化
const bcrypt = require('bcrypt');
// パスワードのハッシュ化
async function hashPassword(password) {
const saltRounds = 12;
return await bcrypt.hash(password, saltRounds);
}
// パスワードの検証
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// 使用例
const hash = await hashPassword('mypassword123');
// → "$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8..."
const isValid = await verifyPassword('mypassword123', hash);
// → true
パスワードは必ずハッシュ化して保存: 平文での保存は絶対にNG。ソルト付きのハッシュ関数(bcrypt、Argon2)を使用します。
用途別の選択
| 用途 | 推奨方式 |
|---|---|
| 通信の暗号化(HTTPS) | TLS(ハイブリッド暗号) |
| ファイルの暗号化 | AES-256-GCM |
| パスワードの保存 | Argon2, bcrypt |
| データの改ざん検知 | HMAC-SHA256 |
| デジタル署名 | Ed25519, ECDSA |
| APIキーの生成 | CSPRNG + Base64 |
まとめ
暗号化は、データセキュリティの基盤となる技術です。共通鍵暗号は高速で大量データの暗号化に適し、公開鍵暗号は鍵配送と認証に適しています。実際のシステムではこれらを組み合わせたハイブリッド暗号が使われます。パスワードの保存には必ずソルト付きのハッシュ関数を使用しましょう。
← 一覧に戻る