- 生成AIデータエンジニア
- DX推進事業マネージャー
- CTO、CTO候補
- Other occupations (5)
- Development
- Business
- Other
公開キーと秘密キーをNode.jsで体験する:仕組みから実装まで
Photo by Ilya Pavlov on Unsplash
ラブレターから始まる暗号の話
もしあなたが好きな人にラブレターを送りたいとき、封筒に鍵をかけて郵送するとしたらどうでしょう?
ただし、その鍵を渡してしまうと誰でもコピーできてしまい、秘密が守れません。
ここで登場するのが 公開キー と 秘密キー です。
「封筒を閉じるための鍵(公開キー)」は相手に渡せるし、世界中の人に配っても構いません。
でも「封筒を開けるための鍵(秘密キー)」は自分だけが持っている。
これがインターネットを支える 非対称暗号 の基本的な発想です。
そしてこの仕組みを、Node.jsのコードで簡単に体験できます。
公開キーと秘密キーの基本
非対称暗号は、二つの役割の異なる鍵をペアで使います。
- 公開キー(Public Key):誰でも知ってよい。暗号化や署名検証に使う。
- 秘密キー(Private Key):絶対に秘匿する。復号や署名生成に使う。
Node.jsで鍵ペアを生成する
Node.jsのcrypto
モジュールを使うと、RSA鍵を簡単に作れます。
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048, // 鍵長(2048ビット推奨)
});
console.log('公開キー:', publicKey.export({ type: 'pkcs1', format: 'pem' }));
console.log('秘密キー:', privateKey.export({ type: 'pkcs1', format: 'pem' }));
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048, // 鍵長(2048ビット推奨)
});
console.log('公開キー:', publicKey.export({ type: 'pkcs1', format: 'pem' }));
console.log('秘密キー:', privateKey.export({ type: 'pkcs1', format: 'pem' }));
これを実行すると、PEM形式の公開鍵と秘密鍵が表示されます。
秘密鍵は 絶対に漏らしてはいけません。
暗号化と復号
まずは公開キーで暗号化し、秘密キーで復号してみましょう。
ここでは暗号化データを Base64で可視化 してみます。
const { publicEncrypt, privateDecrypt } = require('crypto');
const message = "Hello, 公開鍵暗号!";
// 公開キーで暗号化
const encrypted = publicEncrypt(publicKey, Buffer.from(message));
console.log("暗号化されたデータ(Base64):", encrypted.toString("base64"));
// 秘密キーで復号
const decrypted = privateDecrypt(privateKey, encrypted);
console.log("元のメッセージ:", message);
console.log("復号したメッセージ:", decrypted.toString());
const { publicEncrypt, privateDecrypt } = require('crypto');
const message = "Hello, 公開鍵暗号!";
// 公開キーで暗号化
const encrypted = publicEncrypt(publicKey, Buffer.from(message));
console.log("暗号化されたデータ(Base64):", encrypted.toString("base64"));
// 秘密キーで復号
const decrypted = privateDecrypt(privateKey, encrypted);
console.log("元のメッセージ:", message);
console.log("復号したメッセージ:", decrypted.toString());
出力例:
暗号化されたデータ(Base64): Mw3x8kqZt7...(長い文字列)
元のメッセージ: Hello, 公開鍵暗号!
復号したメッセージ: Hello, 公開鍵暗号!
暗号化されたデータ(Base64): Mw3x8kqZt7...(長い文字列)
元のメッセージ: Hello, 公開鍵暗号!
復号したメッセージ: Hello, 公開鍵暗号!
暗号化されたデータは人間には読めないランダムな文字列になります。
これが「ラブレターが他人に盗み見されても解読できない」状態です。
電子署名と検証
公開鍵暗号のもう一つの使い道が「署名」です。
秘密キーで署名し、公開キーで検証することで 送信者が本人であること を証明できます。
const { sign, verify } = require('crypto');
const data = "重要な契約書データ";
// 秘密キーで署名
const signature = sign("sha256", Buffer.from(data), privateKey);
// 公開キーで検証
const isValid = verify("sha256", Buffer.from(data), publicKey, signature);
console.log("署名(Base64):", signature.toString("base64"));
console.log("検証結果:", isValid);
const { sign, verify } = require('crypto');
const data = "重要な契約書データ";
// 秘密キーで署名
const signature = sign("sha256", Buffer.from(data), privateKey);
// 公開キーで検証
const isValid = verify("sha256", Buffer.from(data), publicKey, signature);
console.log("署名(Base64):", signature.toString("base64"));
console.log("検証結果:", isValid);
結果:
署名(Base64): LZs8rQw...(省略)
検証結果: true
署名(Base64): LZs8rQw...(省略)
検証結果: true
もしデータが改ざんされていれば、検証はfalse
になります。
RSAとECCの違い
- RSA
素因数分解が難しいことに基づく。鍵長は2048ビット以上が推奨。 - ECC(楕円曲線暗号)
楕円曲線上の離散対数問題を利用。短い鍵長でも高い安全性を持つ。
→ モバイルやIoTで多用される。
Node.jsでもec
を指定して楕円曲線鍵を生成できます。
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('ec', {
namedCurve: 'secp256k1' // ビットコインやEthereumで使われる曲線
});
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('ec', {
namedCurve: 'secp256k1' // ビットコインやEthereumで使われる曲線
});
実世界での活用例
- HTTPS/TLS:RSAやECDHEで鍵交換
- SSH:GitHubへの認証に公開鍵方式
- 暗号資産:ウォレットの秘密キーが唯一の資産証明
- ソフトウェア配布:npmやaptパッケージの署名検証
まとめ
公開キーと秘密キーは「概念」ではなく、Node.jsで今すぐ試せる技術です。
ぜひ自分の環境でコードを動かして、暗号化データを実際に「目で見て」確認してみてください。