公開鍵・秘密鍵でできること ~暗号化とデジタル署名~
特定のサーバ A が秘密鍵を持ち、任意のクライアントがその対となる公開鍵(サーバ A の公開鍵)を持っているとします。
公開鍵を使って暗号化すると秘密鍵でのみ復号できます。秘密鍵は原則サーバ A 以外には知られないため、サーバ A のみが復号化でき、機密性が確保できます。
逆に、秘密鍵を使って暗号化すると、公開鍵でのみ復号できます。公開鍵は広く知られる前提であるため、機密性の確保はできませんが、「サーバ A の公開鍵で復号化できた」通信というのは、「発信源が間違いなくサーバ A であり、内容は改竄されていない」という完全性・真正性が確保できます。これは主に『デジタル署名 (Digital-Signature)』で使われます。
この性質を利用し、サーバに公開鍵及び秘密鍵をインストールすることで、以下のことができるようになります。
任意のクライアントから特定のサーバ A への通信の機密性確保
サーバ A に一対の公開鍵と秘密鍵をインストールします。そして通信をしたいクライアントが現れたら、そのクライアントに公開鍵を配布します。そのクライアントは通信内容を公開鍵で暗号化をした上でサーバ A へ通信します。
サーバ A は全てのクライアントの通信を、1 つの秘密鍵で復号化して中身を確認することができます。
一方、サーバ A 以外の全世界の機器は秘密鍵が無いので通信は復号できません。公開鍵では復号化出来ないので、公開鍵は盗聴されても影響ありません。
特定のサーバ A から任意のクライアントへの通信の完全性・真正性確保
送信元がサーバ A であること(真正性)、およびサーバ A からの通信が改竄されていないこと(完全性)を、任意のクライアントが検証できます。
サーバ A は通信を送るときに、その通信内容のハッシュ値を秘密鍵で暗号化したデータを一緒に送ります。
クライアントは通信内容のハッシュ値を計算しつつ、付加されたデータを公開鍵で復号化し、同じ値になるかを確認します。合致すればそれはサーバ A からの通信であり、通信内容は途中で改竄されていないということを意味します。
筆跡鑑定のように後から人を特定することができるので『デジタル署名 (Digital-Signature)』と呼ばれています。
最近ではビットコインの multi-sig が話題になりましたが、これは、ビットコインを使う際に、複数人(例えば夫婦)による上記デジタル署名のサインが必要となる、デジタル署名の応用例です。
共通鍵暗号方式と公開鍵暗号方式の比較 メリット・デメリット
共通鍵暗号方式の代表格 AES と公開鍵暗号方式の代表格 RSA を比較します。
比較項目 | AES (共通鍵暗号方式) | RSA (公開鍵暗号方式) |
暗号・復号速度(計算負荷) | 高速(低負荷) | 低速(高負荷) |
鍵をセットするタイミング | 通信開始より前に共有 | 通信開始時に公開鍵を送付 |
クライアント数Nのときの 鍵の必要数 | 2N | N+1 |
2030年以降でも使える強度 のbit数(セキュリティ強度) | 256bit | 3072bit |
一番身近な具体例 https (SSL/TLS) への応用
https (SSL/TLS) では通信の暗号化自体は共通鍵暗号方式を使いますが、その共通鍵の元ネタ (プレマスターシークレット) は公開鍵暗号方式が使われます。
具体的には『DH (Diffie Hellman) 鍵交換』が利用されます。DH では上で説明してきたものとは異なるタイプの公開鍵(DH公開鍵)を使います。このDH公開鍵はサーバとクライアントでそれぞれ異なるのですが、この2つの公開鍵を合体させて共通鍵を生成します。
ですが、DH には認証機能がなく、成り済ましに弱いため、今まで説明した公開鍵(RSA)による認証を行いながら共通鍵の交換を行います。
なので https (SSL/TLS) における RSA 公開鍵(DH 公開鍵ではなく今まで説明してきた公開鍵暗号方式)は『認証』の用途のみに使われます。
このように公開鍵方式と共通鍵方式を両用することで、お互いのメリットをフルに活かしているのです。
例として Web サーバへの https アクセスを考えます。
Web サーバは『秘密鍵』と『公開鍵付き証明書』を持ち、クライアントはサーバへのアクセス時にサーバから公開鍵付き証明書を提示されます。
公開鍵付き証明書は『証明書本体』と『署名』に明確に分かれており、証明書本体には公開鍵が内包されています。一方、署名は、証明書本体をハッシュ化し、秘密鍵で暗号化したものです。
また、証明書本体には『コモンネーム』というサーバへアクセスする際の URL 名が書かれています。例えばwww.yahoo.co.jp の Webサーバなら、コモンネームも www.yahoo.co.jp になります。
クライアントは署名付き証明書を受け取ると、証明書の発行元(ルート)が信頼できるルート証明書かどうかの確認、証明書自体が改竄されていないかの確認、さらに自身がアクセスしているサーバの URL が証明書のコモンネームと同じかの確認をします。
なお、https プロトコルのシーケンスは以下の通りです。
- クライアントがサーバへ https アクセス、その際、自身が使える暗号方式を通知
- サーバは最適な暗号方式を返信しらさらに署名付き証明書をクライアントへ提示
- クライアントはルート証明書の検証、証明書の改竄有無、アクセス URL とコモンネームの合否を確認
- 問題なければ、DH 公開鍵方式により、共通鍵の素(Pre-Master Secret:プリマスターシークレット)を交換してサーバへ送付
- クライアントとサーバはそれぞれ共通鍵の素から共通鍵を生成
- 暗号化通信開始
また、ケースとしては少ないですが、SSL/TLS にはオプションで、クライアントの認証を行うこともできます。

その他の有名な使用例 SSH への応用
SSH サーバは秘密鍵と公開鍵のペアを持っていますが、(SSH2 では)SSH クライアントは SSH サーバへ接続に行くとまず、Diffie Hellman 鍵共有アルゴリズムにより、共通鍵を共有します。
以降の通信は(公開鍵の送付も含め)全てこの共通鍵による暗号化を行った上で行います。これにより公開鍵の改竄を防ぐことができます。
なお、共通鍵は時間経過とともに別の鍵に変えていきます。
SSH サーバの認証(ホスト認証)
共通鍵を交換後、サーバからクライアントへサーバの公開鍵が提示されます。クライアントは、それが初回アクセスであれば、SSH サーバの IP アドレスと紐付けて、その公開鍵をインストールします。
TeraTerm の場合、以下のような画面が表示されます。"Continue"を押下するとクライアントにサーバの公開鍵がインストールされます。
次回以降、同じ IP へのアクセス時に、提示される公開鍵が変わると、警告を出します。単にサーバを更改した場合は問題無いですが、身に覚えが無い場合、成りすましの可能性があるためです(その後の ID パスワード入力が漏洩し、正規のサーバに不正ログインされる可能性がある)。例えば TeraTerm だと以下のような警告画面が出ます。本当に鍵を変えているのであれば "Replace the exist key with this new key" にチェックを入れ、"Continue"を押下し、鍵を置き換えます。
そしてクライアントはある適当な数を公開鍵で暗号化し、それをサーバに送信します。それを受信したサーバは秘密鍵で復号しその数をクライアントに答えます。この数が正しければ SSH サーバが正しい(正しい秘密鍵を持っている)と判断します。これが SSH サーバの認証です。
SSH クライアントの認証
ホスト認証が終わった後は逆に、SSH サーバが SSH クライアントを認証します。これには大きく2つのやり方があります。1 つは ID パスワード認証、もう 1 つは公開鍵認証です。
SSH クライアントの ID パスワード認証
SSH クライアントの ID パスワード認証においては、ID パスワード情報を共通鍵で暗号化してサーバへ送付します。サーバはやはり共通鍵でその情報を復号し、ID パスワードが正しいかどうかを確認します。
SSH クライアントの公開鍵認証
SSH クライアントの公開鍵認証においては、ID パスワードを使わず、クライアントの公開鍵による認証を行います。
この方式を使うためには、SSH クライアントで事前に公開鍵・秘密鍵のペアを生成し、公開鍵を SSH サーバへインストールする必要があります。
例えば user-a というユーザが SSH アクセスするためには、例えば "/home/user-a/.ssh/known_hosts" に公開鍵情報を書き込んでおきます。
あとはホスト認証の逆を行います。つまり、サーバはある適当な数をクライアントの公開鍵で暗号化し、それをクライアントに送信します。それを受信したクライアントは自身の秘密鍵で復号しその数をサーバに答えます。
この数が正しければ SSH クライアントが正しい(正しい秘密鍵を持っている)と判断します。
秘密鍵のセキュリティ、パスフレーズの必要性
秘密鍵はとても重要なものであるがゆえに、メール添付等を含め、安易に複製すべきではありませんし、保護すべきです。Windows 等のいくつかのソフトウェアでは秘密鍵をエクスポートできないような保護設定があります。
また、OpenSSL コマンドや ssh-keygen コマンド等で鍵ペアを作成する際、秘密鍵にパスフレーズを付けて保護することもできます。
このパスフレーズによる保護は、もし秘密鍵の利用タイミングが手動実行時のみであれば、利用のたびにパスフレーズを入力すればそれで問題ありません。ですが例えば Apache の https 用秘密鍵をパスフレーズで保護している環境において、Web サーバが予期せず再起動してしまった場合はパスフレーズの入力を求められ、手動で打ち込まないと httpd が起動しません。
なので自動で秘密鍵が利用されることを期待する環境においては、パスフレーズを設定してはいけいません。
一方、人間がサーバ等の管理のために SSH 接続で秘密鍵を使う場合は、あった方がセキュリティは高くなります。
一見同じものとも思われがちですが、これはニ要素認証の考え方では、異なるものです。二要素認証では、認証の要素として『何を知っている?』『何を持っている?』『何者なのか?』といった種類の中から異なる 2 種類の要素に合格することで認証成功にする、という考え方をします。(同じ要素の中で2回認証するものを2段階認証と言います)
パスフレーズは人間が頭の中で覚えておくのが前提なので『何を知ってるか?』に該当します。一方、秘密鍵の内容は人間が覚えきれるものではなく、『何を持っているか?』に当たります。(具体的には秘密鍵のファイルそのもの)
このように、パスフレーズを設定した秘密鍵を使うことで、二要素認証を実現しているのです。
※ちなみに、『何者なのか?』は主に静脈認証や網膜認証等の生体認証のことです。