cryptography について
Hack23 ISMS Cryptographic Controls Policyに基づく、開発者向けの暗号化セキュリティスキルです。アルゴリズム、鍵管理、TLS、証明書、データ暗号化の要件と実装例を示します。
主な機能
- 01承認・禁止アルゴリズムの提示
- 02鍵の生成・保管・ローテーション要件
- 03TLS・証明書・乱数の規則
- 04保存中・転送中データの暗号化
- 05一般的な暗号処理の例
活用シーン
- 01ポリシーに沿う暗号方式の選定
- 02鍵のライフサイクル管理の確認
- 03TLSと証明書検証の設定
- 04機密データと通信の暗号化
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ hack23/ homepage --skill cryptographyインストール後、Claude Code で/cryptographyを入力して読み込まれたか確認します。
詳細
暗号化スキル
目的
このスキルは、Hack23 ISMS 暗号化制御ポリシーで定義されている暗号化要件を適用します。すべての暗号化処理で承認済みアルゴリズムを使用し、鍵管理のベストプラクティスに従うことを徹底します。
ルール
承認済みアルゴリズム
対称暗号化 — 必須:
- AES-256(Advanced Encryption Standard、256 ビット鍵)
- AES-128(最低要件。AES-256 を推奨)
- ChaCha20-Poly1305(認証付き暗号化用)
非対称暗号化 — 必須:
- RSA-2048 以上(最低 2048 ビット鍵。3072 または 4096 を推奨)
- P-256、P-384、または P-521 曲線を使用する ECDSA
- Ed25519(Curve25519 を使用する EdDSA)
ハッシュ化 — 必須:
- SHA-256(最低要件)
- SHA-384
- SHA-512
- SHA-3 ファミリー
- BLAKE2(高性能が求められるアプリケーション用)
パスワードハッシュ化 — 必須:
- bcrypt(コスト係数は 12 以上)
- scrypt
- Argon2id(推奨)
- SHA-256 を使用する PBKDF2(反復回数は 100,000 回以上)
メッセージ認証 — 必須:
- HMAC-SHA256(最低要件)
- HMAC-SHA512
使用禁止(非推奨/破られているもの):
- DES、3DES
- MD5、SHA-1(チェックサムなど、セキュリティ以外の目的を除く)
- RC4
- 2048 ビット未満の RSA
- 認証付き暗号化を使用しない CBC モード
- ECB モード(いかなる場合も)
TLS/SSL の要件
必須:
- TLS 1.2 以上を使用する
- TLS 1.3 を推奨する
- 強度の高い暗号スイートのみを使用する
- サーバー証明書を検証する
- 高セキュリティのアプリケーションでは証明書ピンニングを使用する
- HSTS(HTTP Strict Transport Security)を適用する
- Perfect Forward Secrecy(PFS)対応の暗号スイートを使用する
TLS 1.2 の承認済み暗号スイート(推奨順):
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS 1.3 の承認済み暗号スイート:
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
禁止:
- SSL 2.0、SSL 3.0、TLS 1.0、TLS 1.1 を使用する
- 輸出グレードの暗号を使用する
- NULL 暗号スイートを使用する
- 匿名暗号スイートを使用する
- 本番環境で自己署名証明書を受け入れる(明示的に信頼された CA を除く)
鍵管理
必須:
- 暗号学的に安全な乱数生成器(CSPRNG)を使用して鍵を生成する
- 鍵を安全に保管する(鍵管理システムを使用し、特に機密性の高い鍵には HSM を使用する)
- ソースコードに鍵をハードコードしない
- 環境変数またはシークレット管理システムを使用する
- 次のスケジュールに従って鍵をローテーションする:
- TLS 証明書:毎年、または有効期限前
- 対称鍵:CONFIDENTIAL データでは毎年、RESTRICTED データでは四半期ごと
- API キー:毎年、または侵害された場合
- パスワード:特権アカウントでは 90 日ごと
- 不要になった鍵を安全に破棄する
- 鍵のライフサイクルイベント(作成、ローテーション、破棄)を記録する
- 鍵の生成と使用を分離する
- 用途ごとに異なる鍵を使用する
- 事業継続のために鍵エスクローを実装する(厳格な管理下で)
鍵長の要件:
- AES:256 ビット(最低 128 ビット)
- RSA:最低 2048 ビット(3072 または 4096 を推奨)
- ECDSA:最低 P-256(P-384 または P-521 を推奨)
- HMAC:最低 256 ビット
禁止:
- 鍵を平文で保管する
- 鍵をバージョン管理にコミットする
- メールまたは暗号化されていないチャネルで鍵を送信する
- 異なるアプリケーションやコンテキスト間で鍵を再利用する
- 脆弱な鍵導出関数を使用する
- 秘密鍵を共有する
乱数生成
必須:
- 暗号学的に安全な PRNG(CSPRNG)を使用する
- Node.js の場合:
crypto.randomBytes()、crypto.randomInt() - Python の場合:
secretsモジュール、os.urandom() - Java の場合:
SecureRandom - ブラウザーの場合:
window.crypto.getRandomValues()
禁止:
- セキュリティ目的で
Math.random()を使用する - 予測可能なシードを使用する
- セキュリティトークン、鍵、または IV に非暗号学的 PRNG を使用する
初期化ベクトル(IV)とノンス
必須:
- 暗号化操作ごとに一意の IV/ノンスを生成します
- CBC モードでは暗号学的に安全な乱数 IV を使用します
- CTR/GCM モードでは連番のノンスを使用します(一意性を確保してください)
- IV を暗号文とともに保存します(IV は秘密ではありません)
- 同じ鍵で IV を再利用してはいけません
禁止:
- CBC モードで予測可能な IV や連番の IV を使用してはいけません
- CTR/GCM モードで同じ鍵のノンスを再利用してはいけません
- IV を秘密として扱ってはいけません(ランダムである必要はありますが、公開してかまいません)
証明書の管理
必須:
- 信頼できる認証局(CA)の証明書を使用します
- 証明書チェーンを検証します
- 証明書の失効状態(CRL/OCSP)を確認します
- 複数のドメインにはサブジェクト代替名(SAN)を使用します
- 証明書の有効期限を監視し、アラートを設定します
- 有効期限前に証明書を更新します(最低30日の余裕を確保してください)
- 自動証明書管理を使用します(例:自動更新付きの Let's Encrypt)
- 秘密鍵を安全に保存します(暗号化し、アクセスを制御します)
- サービス/環境ごとに個別の証明書を使用します
証明書の有効期間:
- 本番環境:最大1年
- 開発/テスト環境:最大90日
- 内部 CA:最大2年
禁止:
- 本番環境で自己署名証明書を使用してはいけません(内部 CA の場合を除く)
- 複数の証明書で秘密鍵を共有してはいけません
- 適切なアクセス制御なしにワイルドカード証明書を使用してはいけません
- 証明書の警告やエラーを無視してはいけません
保存データの暗号化
必須:
- CONFIDENTIAL および RESTRICTED データを保存時に暗号化します
- ノートパソコンやモバイルデバイスにはフルディスク暗号化を使用します
- 機密性の高いデータベースにはデータベース暗号化(TDE)を使用します
- 機密ファイルはクラウドサービスに保存する前に暗号化します
- エンベロープ暗号化を使用します(データ鍵をマスター鍵で暗号化します)
- 暗号鍵は暗号化されたデータとは別に保存します
禁止:
- 暗号化されていない CONFIDENTIAL または RESTRICTED データを保存してはいけません
- 暗号化と認証に同じ鍵を使用してはいけません
- 高機密データに決定論的暗号化を使用してはいけません
通信中の暗号化
必須:
- すべてのネットワーク通信に TLS 1.2 以降を使用します
- CONFIDENTIAL または RESTRICTED データを含むメールを暗号化します(S/MIME または PGP)
- 内部システムへのリモートアクセスには VPN を使用します
- リモート管理には Telnet ではなく SSH を使用します
- すべてのウェブアプリケーションで HTTPS を使用します
- 安全なプロトコルを使用します(FTP ではなく、SFTP、FTPS)
禁止:
- 暗号化されていないチャネルで RESTRICTED データを送信してはいけません
- 暗号化されていないプロトコル(HTTP、FTP、Telnet、TLS なしの SMTP)を使用してはいけません
- 証明書の検証を無効にしてはいけません
例
例1:対称暗号化(Node.js)
const crypto = require('crypto');
// GOOD: AES-256-GCM encryption
function encrypt(plaintext, key) {
// Generate random IV (12 bytes for GCM)
const iv = crypto.randomBytes(12);
// Create cipher
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// Encrypt
let ciphertext = cipher.update(plaintext, 'utf8', 'hex');
ciphertext += cipher.final('hex');
// Get authentication tag
const authTag = cipher.getAuthTag();
// Return IV + authTag + ciphertext
return {
iv: iv.toString('hex'),
authTag: authTag.toString('hex'),
ciphertext: ciphertext
};
}
function decrypt(encrypted, key) {
// Create decipher
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
Buffer.from(encrypted.iv, 'hex')
);
// Set authentication tag
decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));
// Decrypt
let plaintext = decipher.update(encrypted.ciphertext, 'hex', 'utf8');
plaintext += decipher.final('utf8');
return plaintext;
}
// Generate secure key (store securely, don't hardcode!)
const key = crypto.randomBytes(32); // 256 bits
// Usage
const encrypted = encrypt('Sensitive data', key);
console.log('Encrypted:', encrypted);
const decrypted = decrypt(encrypted, key);
console.log('Decrypted:', decrypted);
// BAD: Using deprecated algorithm
function encryptBad(plaintext, key) {
// NEVER use DES!
const cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
return cipher.update(plaintext, 'utf8', 'hex') + cipher.final('hex');
}
例2:パスワードのハッシュ化(bcrypt を使用した Node.js)
const bcrypt = require('bcrypt');
// GOOD: bcrypt with appropriate cost factor
async function hashPassword(password) {
// Cost factor 12 = 2^12 iterations (minimum)
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
return hash;
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
// Usage
const password = 'MySecurePassword123!';
const hash = await hashPassword(password);
console.log('Hash:', hash);
const isValid = await verifyPassword(password, hash);
console.log('Valid:', isValid);
// BAD: Using weak hashing
function hashPasswordBad(password) {
// NEVER use MD5 or SHA-1 for passwords!
return crypto.createHash('md5').update(password).digest('hex');
}
// BAD: Insufficient iterations
async function hashPasswordWeak(password) {
// Cost factor 4 is too weak!
return await bcrypt.hash(password, 4);
}
例3:安全な乱数生成
const crypto = require('crypto');
// GOOD: Cryptographically secure random
function generateToken(length = 32) {
return crypto.randomBytes(length).toString('hex');
}
function generateApiKey() {
return crypto.randomBytes(32).toString('base64');
}
function generateSecurePin(digits = 6) {
const max = Math.pow(10, digits);
return crypto.randomInt(0, max).toString().padStart(digits, '0');
}
// Usage
const sessionToken = generateToken();
const apiKey = generateApiKey();
const pin = generateSecurePin(6);
// BAD: Using Math.random() for security
function generateTokenBad() {
// NEVER use Math.random() for security!
return Math.random().toString(36).substring(2);
}
例4:TLS の設定(Node.js HTTPS サーバー)
const https = require('https');
const fs = require('fs');
// GOOD: Secure TLS configuration
const options = {
key: fs.readFileSync('/path/to/private-key.pem'),
cert: fs.readFileSync('/path/to/certificate.pem'),
ca: fs.readFileSync('/path/to/ca-bundle.pem'),
// TLS 1.2 minimum
minVersion: 'TLSv1.2',
// Prefer TLS 1.3
maxVersion: 'TLSv1.3',
// Strong cipher suites only
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_AES_128_GCM_SHA256',
'TLS_CHACHA20_POLY1305_SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-AES128-GCM-SHA256'
].join(':'),
// Prefer server cipher order
honorCipherOrder: true,
// Enable Perfect Forward Secrecy
ecdhCurve: 'prime256v1:secp384r1:secp521r1',
// Require client certificate (if needed)
requestCert: false,
rejectUnauthorized: true
};
const server = https.createServer(options, (req, res) => {
// Set security headers
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.writeHead(200);
res.end('Secure connection');
});
server.listen(443);
// BAD: Weak TLS configuration
const optionsBad = {
key: fs.readFileSync('/path/to/private-key.pem'),
cert: fs.readFileSync('/path/to/certificate.pem'),
// NEVER allow TLS 1.0/1.1
minVersion: 'TLSv1.0', // TOO WEAK!
// Allowing weak ciphers
ciphers: 'ALL', // INSECURE!
// Not rejecting unauthorized
rejectUnauthorized: false // DANGEROUS!
};
例5:鍵導出(PBKDF2)
const crypto = require('crypto');
// Derive encryption key from password
function deriveKey(password, salt, keyLength = 32) {
// Use PBKDF2 with SHA-256, 100,000 iterations minimum
return crypto.pbkdf2Sync(
password,
salt,
100000, // iterations (minimum)
keyLength,
'sha256'
);
}
// Usage
const password = 'UserPassword123!';
const salt = crypto.randomBytes(16); // Store salt with encrypted data
const key = deriveKey(password, salt, 32); // 256-bit key
console.log('Derived key:', key.toString('hex'));
// BAD: Weak key derivation
function deriveKeyWeak(password) {
// NEVER use simple hashing for key derivation!
return crypto.createHash('sha256').update(password).digest();
}
例6:安全なファイル暗号化
const crypto = require('crypto');
const fs = require('fs').promises;
async function encryptFile(inputPath, outputPath, key) {
// Read file
const plaintext = await fs.readFile(inputPath);
// Generate IV
const iv = crypto.randomBytes(12);
// Encrypt
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const ciphertext = Buffer.concat([
cipher.update(plaintext),
cipher.final()
]);
// Get auth tag
const authTag = cipher.getAuthTag();
// Write IV + authTag + ciphertext
const encrypted = Buffer.concat([iv, authTag, ciphertext]);
await fs.writeFile(outputPath, encrypted);
}
async function decryptFile(inputPath, outputPath, key) {
// Read encrypted file
const encrypted = await fs.readFile(inputPath);
// Extract IV, auth tag, and ciphertext
const iv = encrypted.slice(0, 12);
const authTag = encrypted.slice(12, 28);
const ciphertext = encrypted.slice(28);
// Decrypt
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
const plaintext = Buffer.concat([
decipher.update(ciphertext),
decipher.final()
]);
// Write decrypted file
await fs.writeFile(outputPath, plaintext);
}
// Usage
const key = crypto.randomBytes(32);
await encryptFile('sensitive.pdf', 'sensitive.pdf.enc', key);
await decryptFile('sensitive.pdf.enc', 'sensitive-decrypted.pdf', key);
例7:証明書の検証
const https = require('https');
const tls = require('tls');
// GOOD: Verify certificate
function makeSecureRequest(url) {
return new Promise((resolve, reject) => {
https.get(url, {
// Verify certificate chain
rejectUnauthorized: true,
// Check hostname
checkServerIdentity: (hostname, cert) => {
const err = tls.checkServerIdentity(hostname, cert);
if (err) {
return err;
}
// Additional checks
const now = new Date();
const notBefore = new Date(cert.valid_from);
const notAfter = new Date(cert.valid_to);
if (now < notBefore || now > notAfter) {
return new Error('Certificate not valid for current date');
}
return undefined;
}
}, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
}
// BAD: Skipping certificate verification
function makeInsecureRequest(url) {
return new Promise((resolve, reject) => {
https.get(url, {
// NEVER disable certificate verification!
rejectUnauthorized: false // DANGEROUS!
}, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
}
関連する ISMS ポリシー
- 暗号化制御ポリシー - 暗号化に関する主要なポリシー
- データ分類ポリシー - データ分類と暗号化の要件
- セキュア開発ポリシー - コードにおける暗号化の実装
関連ドキュメント
- SECURITY_ARCHITECTURE.md - アーキテクチャにおける暗号化制御
- secure-development SKILL.md - セキュアコーディングの実践
- data-classification SKILL.md - 分類に応じた暗号化要件
コンプライアンス対応
ISO 27001:2022
- A.8.24 暗号化の使用
NIST サイバーセキュリティフレームワーク
- PR.DS-1:保存データを保護します
- PR.DS-2:通信中のデータを保護します
CIS Controls
- Control 3:データ保護
- 3.10 転送中の機密データを暗号化する
- 3.11 保存データを暗号化する
鍵のローテーションスケジュール
| 鍵の種類 | ローテーション頻度 | 即時ローテーションのトリガー |
|---|---|---|
| TLS 証明書 | 年次 | 侵害、アルゴリズムの脆弱性 |
| 対称鍵(RESTRICTED) | 四半期ごと | 侵害、従業員の退職 |
| 対称鍵(CONFIDENTIAL) | 年次 | 侵害 |
| API キー | 年次 | 侵害、従業員の退職 |
| SSH キー | 2 年ごと | 侵害 |
| ルート CA キー | 10 年ごと | 侵害 |
| データベース暗号化キー | 2 年ごと | 侵害 |
適用
暗号要件への違反:
- 重大(禁止アルゴリズムの使用、ハードコードされたキー):デプロイをブロック
- 高(脆弱な設定、暗号化の欠如):即時の修正を必須とする
- 中(最適でない設定):スプリント内に修正
コメント
Markdown 対応