0.はじめに
セキュリティ(ソリューション)に携わって早20数年の元システムエンジニアです。
私が新人システムエンジニアとしてSIerで働き始めたころ、
会社から支給されたパソコンにはウイルス対策ソフトがインストールされていませんでした。
(ウソだろ、と思うかもしれませんが、当時のセキュリティ意識はそんなもんでした)
今ではセキュリティ対策は経営課題の一つとなっていることを考えると、
長生きすると色々あるなあと感じてしまいます。
(当時は「セキュリティ?なにそれ?」みたいな感じでした…)
さて、そんなこんなで今回はセキュリティの基礎である暗号の一つ「公開鍵暗号」についてです。
1.共通鍵暗号と公開鍵暗号の基礎
一般的な暗号の仕組みとして有名なものが2つあります。「共通鍵暗号」と「公開鍵暗号」です。
公開鍵暗号の前に、共通鍵暗号を説明します。
1-1.共通鍵暗号
共通鍵暗号は、暗号と復号に同じ鍵を使用します(共通の鍵を使用するので、共通鍵暗号です)。
簡単な図を用いて説明します。
毎度おなじみアリスとボブです。
左にいるアリスが、テキストメッセージを共通鍵で暗号化し、右にいるボブが、受け取った暗号化メッセージを(同じ)共通鍵で復号しています。
共通鍵がないと、次の状態になってしまいます。
・アリスはテキストメッセージを暗号化できない
・ボブは暗号化メッセージを復号できない
1-1-1.技術者向け:opensslでの実行結果
せっかくなので、opensslで暗号・復号を試してみましょう。
環境は何でもよいですが、私はAlmaLinuxを使用します。
$ cat /etc/almalinux-release
AlmaLinux release 9.6 (Sage Margay)
opensslのバージョンを確認します。
$ openssl version
OpenSSL 3.2.2 4 Jun 2024 (Library: OpenSSL 3.2.2 4 Jun 2024)
次に準備。
今回はAES-256-CTRで試します。
(深い理由はないです、この環境で試せる暗号方式だったので)
アリス側の作業です。暗号鍵(共通鍵)の作成。
$ openssl rand 32 > symmetric.key
IVの作成。
※IV…Initialization Vector(初期化ベクトル)。
$ openssl rand 16 > iv.bin
テキストメッセージの作成。
$ echo "My name is Alice." > plain.txt
$ cat plain.txt
My name is Alice.
さて、このテキストメッセージを暗号化します。
テキストメッセージ(plain.txt)が暗号化されます(ciphertext.bin)。
KEYHEX=$(xxd -p -c 256 symmetric.key | tr -d '\n')
IVHEX=$(xxd -p -c 256 iv.bin | tr -d '\n')
openssl enc -aes-256-ctr -nosalt \
-K "$KEYHEX" -iv "$IVHEX" \
-in plain.txt -out ciphertext.bin
$ cat ciphertext.bin
��,7��P��K�k6�+�
暗号化されたメッセージはバイナリデータなので、文字化けしていますね。
(本筋とは関係ないですが)見やすい文字に変換してみましょう。
$ xxd ciphertext.bin
00000000: 0b81 842c 37f2 b650 acc5 4baf 156b 36f5 ...,7..P..K..k6.
00000010: 2be3 +.
ここまでが、アリス側の作業ですね。
(暗号化されたメッセージと共通鍵は、何らかの方法でボブ側に送ります)
ここからが、ボブ側の作業です。
暗号化されたメッセージを復号します。
KEYHEX=$(xxd -p -c 256 symmetric.key | tr -d '\n')
IVHEX=$(xxd -p -c 256 iv.bin | tr -d '\n')
openssl enc -d -aes-256-ctr -nosalt \
-K "$KEYHEX" -iv "$IVHEX" \
-in ciphertext.bin -out decrypted.txt
$ ls decrypted.txt
decrypted.txt
$ cat decrypted.txt
My name is Alice.
きちんと復号できてますね、よしよし。
1-1-2.共通鍵暗号の課題
ところで、共通鍵暗号には課題があります。
何でしょうか?
(その理由が、まさしく公開鍵暗号につながります)
それは、「鍵の受け渡し(鍵配送)」です。
共通鍵暗号では、鍵が無いと、暗号/復号ができません。そのため、何らかの方法で鍵を相手と共有する必要があります。
さて、鍵を安全に受け渡すにはどうしたらよいでしょうか?
そのままメールに添付するのは危険ですよね?
じゃあ、「暗号化」して添付する??
じゃあ、それを暗号・復号するための鍵はどうやって共有する???
みたいな感じで、迷宮に迷い込んでしまいます…
Ohhh、困った…
昔の人は考えました。新しい暗号方式が必要だと。
それが、公開鍵暗号です。
(暗号に歴史ありです)
1-2.公開鍵暗号
公開鍵暗号は、暗号と復号に別の鍵を使用します。
簡単な図を用いて説明します。
こちらも毎度おなじみアリスとボブです。
左にいるアリスが、テキストメッセージを公開鍵で暗号化し、右にいるボブが、受け取った暗号化メッセージを秘密鍵で復号しています。
ここでのポイントは、暗号と復号で使用する鍵が異なるということです。
(暗号には公開鍵、復号には秘密鍵)
1-2-1. 公開鍵暗号のメリット
さて、この公開鍵暗号、さきほどの共通鍵暗号の課題が解消されています。
どういうことかというと、この「公開鍵」、暗号する機能は持っていますが、復号する機能は持っていません。そのため、誰かに盗まれないように安全に保護しなくても大丈夫なんです。
そのため、鍵の受け渡し(鍵配送)をどうするか(どうやって安全に配送するか)に頭を悩ませなくて済みます。
1-2-2. 技術者向け:opensslでの実行結果
さて、せっかくなので、こちらもopensslで暗号・復号を試してみましょう。
今回はRSAで試します(暗号・復号を試すため)。
ボブ側の作業です。まず、秘密鍵の作成。
$ openssl genpkey -algorithm RSA -out rsa_private.pem -pkeyopt rsa_keygen_bits:2048
次に、公開鍵の作成。
$ openssl pkey -in rsa_private.pem -pubout -out rsa_public.pem
ここまでが、ボブ側の作業です。
(公開鍵は、何らかの方法でアリス側に送ります)
ここからが、アリス側の作業です。
テキストメッセージを作成します。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
このメッセージを暗号化します。
$ openssl pkeyutl -encrypt -pubin -inkey rsa_public.pem -in rsa_plain.txt -out rsa_encrypted.bin
(暗号化されたメッセージをcatで見ると、ターミナルが文字化けするので、今回はスキップ)
なお、見やすい文字に変換することはできます。
$ openssl base64 -in rsa_encrypted.bin
d6Hv3nd/3We1Z/9kMwqmhckIUdIUo06TVlLaclPVWhCH8BGtko7cg+EFB6Fx+qT/
hgATgLUlqJvblw65fusOwc3DJFbGlTN7mvuxYBPN2XO8UHYJ5W9av+iwXvMGFJfm
f94HYNl3JGmR5ouGwPKBd+M2zmuf4LiBDFfPzYmdvY1llx6XZCRrm6D62qXROhsQ
lavvPQkGZT2w+k4Y2Enc/jAccldnR6aQcEeSLKNUqw7LSmnjOyTuAjIBgy+yLwWn
nKkvyZria+l9G+KeR0o9n6SLSSOu1d4CWaPAxiRnIXtzOA0ukacZ8vl+LuvAtxOq
5B1rX8xbOcM+SaFlG0HVbg==
ここまでが、アリス側の作業です。
(暗号化されたメッセージは、何らかの方法でボブ側に送ります)
ここからが、ボブ側の作業です。
暗号化されたメッセージを復号します。
$ openssl pkeyutl -decrypt -inkey rsa_private.pem -in rsa_encrypted.bin -out rsa_decrypted.txt
復号したメッセージを確認します。
$ cat rsa_decrypted.txt
My name is Alice.
きちんと復号できてますね、よかったよかった。
2. 公開鍵暗号は3種類ある
さて、ここまで共通鍵暗号と公開鍵暗号について説明してきました。
公開鍵暗号は
- 公開鍵で暗号する
- 秘密鍵で復号する
という仕組みです。しかし、実は公開鍵暗号には他の利用方法もあります。
2-1. 3つの顔を持つ公開鍵暗号
実は公開鍵暗号には3つの顔(3つの側面)があります。
それは
- 暗号(守秘)
- 署名
- 鍵同意(鍵共有)
です。
2-1-1. 暗号(守秘)
公開鍵暗号1つ目の顔は「暗号」です。「守秘」という言い方もあります。
その名の通り「暗号」するために使用する方法で、
先ほど説明した「公開鍵で暗号して、秘密鍵で復号」のやつです。
一般的に有名なのは、この「暗号」だと思います。
(が、実際に公開鍵暗号を「暗号」として使う事例は減ってきているという現実を、特にシステムエンジニアは知っておいてください)
2-1-2. 署名
公開鍵暗号2つ目の顔は「署名」です。
後ほど図とともに説明します。
2-1-3. 鍵同意(鍵共有)
公開鍵暗号3つ目の顔は「鍵同意(鍵共有)」です。
公開鍵暗号の中でも、ちょっと変わった使い方をするものとなっています。
「暗号」と「署名」は、一方が秘密鍵、もう一方が公開鍵を持ちます。
しかし「鍵同意(鍵共有)」では、お互いが秘密鍵と公開鍵の両方を持ちます。
その状態で、お互いが同じ共通鍵を持つ(共有する)ための仕組みなんです!
こちらも後ほど図とともに説明します。
2-2. 公開鍵暗号の署名
公開鍵暗号の署名を簡単な図を用いて説明します。
(といいつつ、それなりに複雑になってしまっています)
こちらも毎度おなじみアリスとボブです。
左にいるアリスが、テキストメッセージを基に署名を作成します。
メッセージそのものを署名するのではなく、いったんメッセージをハッシュにして、そのハッシュ値に対して秘密鍵で署名します。
右にいるボブは、メッセージと署名を受け取り、公開鍵を基に署名検証します。署名が正しければOK、署名が間違っていればNGとなります。
2-2-1. 技術者向け:opensslでの実行結果
さて、せっかくなので、こちらもopensslで暗号・復号を試してみましょう。
前回同様、RSAで試します(RSAは暗号・復号だけでなく、署名・署名検証でも使えます)。
アリス側の作業です。まず、秘密鍵の作成。
$ openssl genpkey -algorithm RSA -out rsa_private.pem -pkeyopt rsa_keygen_bits:2048
次に、公開鍵の作成。
$ openssl pkey -in rsa_private.pem -pubout -out rsa_public.pem
テキストメッセージを作成します。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
このメッセージをハッシュ化します。
$ openssl dgst -sha256 -binary rsa_plain.txt > rsa_plain.hash_sha256
ハッシュ値はバイナリです。
念のため、中身を見てみましょう。
$ openssl base64 -in rsa_plain.hash_sha256
tC3aKaEPmtrdoDX7TdqA+5pbL324Tc4qOzQ2nrO0ncA=
それでは、ハッシュ値を基に署名します。
$ openssl pkeyutl -sign -inkey rsa_private.pem -in rsa_plain.hash_sha256 -out rsa_plain.sig -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss
rsa_plain.sigというファイルが作成されています。
ここまでが、アリス側の作業です。
(公開鍵、テキストメッセージ、署名ファイルは、何らかの方法でボブ側に送ります)
ここからが、ボブ側の作業です。
まず、テキストメッセージをハッシュ化します。
$ openssl dgst -sha256 -binary rsa_plain.txt > rsa_plain_bob.hash_sha256
次に署名が正しいかどうか、署名検証します。
$ openssl pkeyutl -verify -pubin -inkey rsa_public.pem -in rsa_plain_bob.hash_sha256 -sigfile rsa_plain.sig -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss
Signature Verified Successfully
「Signature Verified Successfully」となっているので、署名が正しいことが検証できました。めでたしめでたし。
2-3. 公開鍵暗号の鍵同意(鍵共有)
公開鍵暗号の鍵同意(鍵共有)を簡単な図を用いて説明します。
(といいつつ、これもそれなりに複雑になってしまっています)
こちらも毎度おなじみアリスとボブです。
鍵同意(鍵共有)は、公開鍵暗号を基に共通鍵を生成します。
まず、アリスとボブが、それぞれ秘密鍵と公開鍵を作成します。
(A秘密鍵…アリスの秘密鍵、A公開鍵…アリスの公開鍵、B秘密鍵…ボブの秘密鍵、B公開鍵…ボブの公開鍵)
次に、アリスは自分の公開鍵(A公開鍵)をボブに渡し、逆にボブは自分の公開鍵(B公開鍵)をアリスに渡します。
ここから、アリスは自分の秘密鍵(A秘密鍵)とボブの公開鍵(B公開鍵)を用いて、共通鍵を生成します。
同じように、ボブは自分の秘密鍵(B秘密鍵)とアリスの公開鍵(A公開鍵)を用いて、共通鍵を生成します。
それぞれで生成した共通鍵は、なんと同じものになります!
(なんで?と思うかもしれませんが、数学的にそういう風になるそうです)
※この辺りは専門的な話になりますので、割愛させていただきます
アリスはテキストメッセージを共通鍵で暗号化します。
暗号化されたデータをボブは共通鍵で復号します。
2-3-1. 技術者向け:opensslでの実行結果
opensslで鍵同意(と暗号&復号)を試してみましょう。
鍵同意は、アリス側とボブ側で色々作業があります(ので混乱しないようにしてください)。
まず、アリス側。
テキストメッセージを作成します。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
秘密鍵の作成。
$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out alice_private.pem
公開鍵の作成。
$ openssl pkey -in alice_private.pem -pubout -out alice_public.pem
ボブ側。
秘密鍵の作成。
$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out bob_private.pem
公開鍵の作成。
$ openssl pkey -in bob_private.pem -pubout -out bob_public.pem
アリスの公開鍵をボブに、ボブの公開鍵をアリスに渡します。
(渡し方はお任せします、公開鍵なので)
また、アリス側の作業。
共通鍵(の元になる情報)の作成。
$ openssl pkeyutl -derive -inkey alice_private.pem -peerkey bob_public.pem -out alice_secret.bin
ボブ側。
同様に共通鍵(の元になる情報)の作成。
$ openssl pkeyutl -derive -inkey bob_private.pem -peerkey alice_public.pem -out bob_secret.bin
アリス側。
共通鍵とIVの作成。
$ openssl dgst -sha256 -binary alice_secret.bin > aes_key.bin
$ openssl dgst -sha256 -binary -mac HMAC -macopt hexkey:00 alice_secret.bin | head -c 16 > aes_iv.bin
ボブ側。
共通鍵とIVの作成。
$ openssl dgst -sha256 -binary bob_secret.bin > aes_key.bin
$ openssl dgst -sha256 -binary -mac HMAC -macopt hexkey:00 bob_secret.bin | head -c 16 > aes_iv.bin
アリス側。
テキストメッセージを暗号化します。
$ openssl enc -aes-256-cbc -e -in alice_plain.txt -out alice_cipher.bin -K "$(xxd -p -c 256 aes_key.bin)" -iv "$(xxd -p -c 256 aes_iv.bin)"
念のため、暗号化されていることの確認。
$ cat alice_cipher.bin
uEۻƽo�/��� 9���cG�gװ�d(���f
(暗号化されたメッセージは、何らかの方法でボブ側に送ります)
ボブ側。
テキストメッセージを復号します。
$ openssl enc -aes-256-cbc -d -in alice_cipher.bin -out bob_decrypted.txt -K "$(xxd -p -c 256 aes_key.bin)" -iv "$(xxd -p -c 256 aes_iv.bin)"
メッセージが復号されていることの確認。
$ cat bob_decrypted.txt
My name is Alice.
めでたしめでたし。
3. おわりに
今回は、(共通鍵暗号と)公開鍵暗号について学びました。
公開鍵「暗号」という名称なので、「暗号・復号」に使われるものだと思っている方もいるかもしれませんが、
実際にはそれ以外の用途でも使われています。
インターネットの暗号通信であるTLSや証明書にも、この公開鍵暗号(と共通鍵暗号)が使用されています。
システムエンジニア(特にセキュリティに携わる方)にとっては、とても重要な領域です。
ぜひ覚えておいてください。
(気になる方は、もっと専門的な本もおすすめです)
3-1. 次回予告?
検討中ですが、やっぱり「TLS」か「証明書」ですかね。
これはこれで奥が深いテーマなので、できる限り簡潔に説明できればと考えています。
97.参考文献
98.更新履歴
- 2026.02.13 初版



