導入
皆様お久しぶりです。
勉強するぞと息巻いておきながら、EscapeFromTarkovに生活を乗っ取られているシロクマです。
最近業務で簡単に暗号化について学ぶ機会があった為概要をまとめてみようと思います。
主要な暗号化の形式
基本情報の勉強をしていると良く出てくるのが、
共通鍵方式(対称鍵暗号)、公開鍵方式(非対称鍵暗号)の2種類です。
一旦概要をまとめてみましょう
| 共通鍵方式(対称鍵暗号) | 公開鍵方式(非対称鍵暗号) | |
|---|---|---|
| 主な方式 | AES,DES,3DES | RSA,ECDSA/ECDH |
| 特徴 | - 高速、大量のデータの暗号化に向いている鍵共有が難しい | 安全に鍵交換できる、認証に使える、計算が重い |
| 使用例 | HTTPS通信の実データ、データベースの暗号化、ローカルファイルの暗号化 | HTTPSの鍵交換、JWT署名、SSHの公開鍵認証 |
ぶっちゃけ知らんがなって感じですよね(笑)
もう少しかみ砕いてみましょう。
共通鍵 : 早いからデータの受け渡しなどで大量のデータを扱える!
公開鍵 : 鍵を安全に受け渡せるから認証などのセキュリティが大切な所に使われる!
大体こんな感じだと思います。
ちなみに最近は組み合わせて使うのが主流らしいですね(気になったら調べてみてね)
実際に動かして確認してみる
実はChatGPTを有料版にアップグレードしたので、
実際にコードを出力してイメージを膨らませてみましょう(低速にならないから仕事でも助かります、、)
共通鍵方式
#!/usr/bin/env node
/**
* 共通鍵方式 AES-256-CBC で
* 暗号化 / 復号化 を行う CLI ツール
*
* 使い方:
* node crypto-tool.js encrypt "平文"
* node crypto-tool.js decrypt "暗号文"
*/
const crypto = require("crypto");
// =============================
// 設定(共通鍵と IV の管理)
// =============================
// ★ 共通鍵(32バイト必要 → 32文字のランダム文字列にしてください)
const SECRET_KEY = process.env.AES_KEY || "12345678901234567890123456789012"; // 必ず変更する
// ★ IV(初期ベクトル 16バイト)
const IV = process.env.AES_IV || "1234567890123456"; // 必ず変更する
// =============================
// 暗号化
// =============================
function encrypt(text) {
const cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(SECRET_KEY), IV);
let encrypted = cipher.update(text, "utf8", "base64");
encrypted += cipher.final("base64");
return encrypted;
}
// =============================
// 復号化
// =============================
function decrypt(base64Text) {
const decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(SECRET_KEY), IV);
let decrypted = decipher.update(base64Text, "base64", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
}
// =============================
// CLI 実行部分
// =============================
const [,, command, value] = process.argv;
if (!command || !value) {
console.log("使い方:");
console.log(" node crypto-tool.js encrypt \"平文\"");
console.log(" node crypto-tool.js decrypt \"暗号文\"");
process.exit(1);
}
if (command === "encrypt") {
console.log(encrypt(value));
} else if (command === "decrypt") {
console.log(decrypt(value));
} else {
console.log("不明なコマンドです: " + command);
}
公開鍵方式
鍵生成
// generate-keys.js
const { generateKeyPairSync } = require('crypto');
const fs = require('fs');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
fs.writeFileSync('public.pem', publicKey);
fs.writeFileSync('private.pem', privateKey);
console.log('RSA キーを生成しました!');
暗号化
// generate-keys.js
const { generateKeyPairSync } = require('crypto');
const fs = require('fs');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
fs.writeFileSync('public.pem', publicKey);
fs.writeFileSync('private.pem', privateKey);
console.log('RSA キーを生成しました!');
複合化
// encrypt.js
const fs = require("fs");
const crypto = require("crypto");
// 引数読み取り
const text = process.argv[2];
if (!text) {
console.error("Usage: node encrypt \"text\"");
process.exit(1);
}
// 公開鍵を読み込む
const publicKey = fs.readFileSync("./public.pem", "utf8");
// 公開鍵で暗号化
const encrypted = crypto.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
},
Buffer.from(text, "utf8")
);
// Base64で出力
console.log(encrypted.toString("base64"));
という事で出力したので確認していきましょう。
まずは共通鍵からですね
コードの中に暗号化に必要な物が入っています。
// ★ 共通鍵(32バイト必要 → 32文字のランダム文字列にしてください)
const SECRET_KEY = process.env.AES_KEY || "12345678901234567890123456789012"; // 必ず変更する
// ★ IV(初期ベクトル 16バイト)
const IV = process.env.AES_IV || "1234567890123456"; // 必ず変更する
VsCodeのターミナルで叩いてみると、、、
node crypto-tool.js encrypt "Hello World"
bdwO/5C8a+pliIoIXtuzfA==
node crypto-tool.js decrypt "bdwO/5C8a+pliIoIXtuzfA=="
Hello World
無事暗号化されたHello Worldが物に戻りました!
共通鍵は使うものが暗号化と複合化で変わらないのでイメージしやすいですね。
続いて公開鍵も試してみる
まずは鍵を生成します。
node generate-keys.js ファイルを実行すると公開鍵と秘密鍵がprivate.pemとpublic.pemに入っています
では生成された鍵を使って暗号化と複合化を行います
node encrypt "Hello World"
DroYpuuyHDsOhQQ+fKBo3kwrT6O+DTbrxdVExRb4sNY3zLuPcHk5ZcNRhg/4s0MeedqLmeCEYfLQ4s9X8woRXRh5XDKaS5/FcorfCzvbbljq2AKcd+U2BnLiAwSk5bm97BJ13d35Qnmbjk9M2pP07i6p4cnd5U0WGjX/JHEiz+FV5BBlH9QQo/vDiOHQzJg+SF7RqTqCGljkIs3Cq0kOCKlmn51cy/WidxBxE9qYINwSEQXl0qbDfe1FMom+t2PCCJNyI0iAXNpM1dnhZfXalJtckm2cY55A60akti0RakJbln4XLhlblwDmFDoe4la9pfdIKR0GoSNjwOFdSl2U6w==
node decrypt DroYpuuyHDsOhQQ+fKBo3kwrT6O+DTbrxdVExRb4sNY3zLuPcHk5ZcNRhg/4s0MeedqLmeCEYfLQ4s9X8woRXRh5XDKaS5/FcorfCzvbbljq2AKcd+U2BnLiAwSk5bm97BJ13d35Qnmbjk9M2pP07i6p4cnd5U0WGjX/JHEiz+FV5BBlH9QQo/vDiOHQzJg+SF7RqTqCGljkIs3Cq0kOCKlmn51cy/WidxBxE9qYINwSEQXl0qbDfe1FMom+t2PCCJNyI0iAXNpM1dnhZfXalJtckm2cY55A60akti0RakJbln4XLhlblwDmFDoe4la9pfdIKR0GoSNjwOFdSl2U6w==
Hello World
という訳で無事戻りました!
公開鍵方式は暗号化用の鍵と複合化用の鍵がありますが、
共通鍵方式は暗号化にIV(Initialization Vector)を使うので、その辺りは似ているかもしれないですね。
あとがき
この辺りは実際に動かしてみるとイメージし易いと思うので実際に動かしてみてください。
今回の暗号化の動作を確認したうえで、次回は基本情報の暗号化周りの問題を少し解説してみようと思います
ではまた次回お会いしましょう![]()