暗号化の基礎 - データを守る暗号技術

14分 で読める | 2025.12.06

暗号化とは

暗号化は、データを第三者が読めない形式に変換する技術です。正しい鍵を持つ者だけが元のデータを復元(復号)できます。

なぜ必要か: 通信の盗聴、データベースへの不正アクセス、端末の紛失など、データが第三者の手に渡るリスクに対処するためです。

暗号化の種類

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["平文"]

代表的なアルゴリズム

アルゴリズム鍵長特徴
AES128/192/256ビット現在の標準、高速
ChaCha20256ビットモバイル向け、高速
3DES168ビットレガシー、非推奨

実装例

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-256256ビット一般的なハッシュ
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

まとめ

暗号化は、データセキュリティの基盤となる技術です。共通鍵暗号は高速で大量データの暗号化に適し、公開鍵暗号は鍵配送と認証に適しています。実際のシステムではこれらを組み合わせたハイブリッド暗号が使われます。パスワードの保存には必ずソルト付きのハッシュ関数を使用しましょう。

← 一覧に戻る