公開鍵暗号について理解が足りていなかったのでメモ

これは何?


github にコミットする時とか、heroku にデプロイする時とか、
認証に公開鍵使うけど、いまいちちゃんと理解していないのでまとめた


目次

暗号化の方法

共通鍵暗号


送信者と受信者が共通の秘密鍵を持って、暗号化と複合を行う
たとえばこんな感じ


平文 : 1234
秘密鍵 : 5678
暗号化 : 1234 x 5678
暗号文 : 7006652
復号化 : 7006652 / 5678

  • 送信者側は、平文を、秘密鍵で暗号化して、暗号文を受信者に送る
  • 受信者は、暗号文を、秘密鍵で復号化して、平文を得る
共通鍵暗号の弱点
  • 最初に鍵を受信者に渡す必要があるが、その時に盗聴されるリスクがある
    • 渡す時暗号化すれば良いけど、その暗号化の鍵を... となる
  • 多人数で秘密の通信をしたい場合、組み合わせの数だけ鍵が必要になる
    • AとB が、Cには秘密の通信をする場合
    • AとC が、Bには秘密の通信をする場合
    • BとC が、Aには秘密の通信をする場合
    • それぞれ鍵が必要になる

公開鍵暗号


公開鍵と、秘密鍵の2つを用意
暗号化には、公開鍵を使って復号には、秘密鍵を使う
公開鍵は暗号化するだけで、復号化できないので、知らない人に渡っても通信の内容がバレることは無い
現在の主流


上記の条件を満たす秘密鍵、公開鍵の作り方はややこしかったので飛ばす
とりあえず、そういうものを使って暗号化していると理解

でも、公開鍵だと一方的な通信しかできないよね?


なので実際の所は、公開鍵を使ってそのセッション限りの共通鍵を渡して、
そのセッションの間だけ、共通鍵暗号で通信するって方法がスタンダードらしい


んでもうちょっと具体的な話
公開鍵暗号が、HTTPSや、SSHでどんな風に使われているかを解説

HTTPS


HTTPが、TLS/SSL で暗号化されている事を示すURLスキーム

TLS/SSL


セキュリティーを要求される通信の為のプロトコル

  1. クライアントは、公開鍵証明書をサーバから受けとる
  2. クライアントは、公開鍵証明書から、公開鍵を取得。それを使って乱数を暗号化してサーバに送る
  3. サーバは、乱数を元にした共通鍵を作って、クライアントに送る
  4. 共通鍵で通信する
  5. 通信が終わったら共通鍵を破棄する


こういう、秘密鍵と共通鍵を組み合わせた方法を、ハイブリッド暗号化方式というらしい

公開鍵証明書って?


公開鍵単体では、その公開鍵がどこのものであるかは分からない
なので、以下のような方法で公開鍵を偽って、盗聴することが可能

  1. 悪意のあるC が、Aのものと偽って公開鍵を配布する
  2. それを知らないBが、Cが作った公開鍵で、Aに暗号化情報を送る
  3. Cが、Bの通信を傍受できるならば、通信内容を復号できてしまう


そんな問題を回避するために、公開鍵の所有者を信頼出来る第三者機関(認証局)が審査して、発行される証明書が、公開鍵証明書

  • んで、認証局が審査をすることで、公開鍵の所有者を保証する仕組みのことを公開鍵基盤(PKI: public key infrastructure)というらしい
証明書の中身


メジャーな証明書の規格、X.509 だと

認証の流れ
  1. 認証局は、秘密鍵(署名用)と、公開鍵(検証用)を用意する
  2. 認証局は、秘密鍵で証明書のデータに署名を行う。この署名を証明書に添付する。
  3. クライアントは、認証局から公開鍵(検証用)を受け取る
  4. 電子署名を公開鍵(検証用)で検証する。
  5. 検証を通れば、その証明書は改ざんされていないので、信用されていると見なせる
認証局の公開鍵はだれが証明するの?


より上位の認証局が認証して、それをそらに上位の認証局が..となっている
なので、最上位の認証局(ルート認証局)は、だれも認証していない

ルート認証局の情報は予めブラウザに入っており、予め信頼できる認証局と見なされている

SSH


Secure Shell


暗号や認証の技術を利用して、安全にリモートコンピュータと通信するためのプロトコル
Telnetだと平文でパスワードサーバに送るから危なかっかしい
SSHは、ハイブリッド暗号化方式(上記SSHで言及)で通信するから盗聴されても安心
また、公開鍵を使ったパスワードを使わない認証が可能

公開鍵認証


公開鍵を使った認証方式

  1. クライアントは、秘密鍵(復号用)と、公開鍵(暗号化用)を用意する
  2. クライアントは、サーバに公開鍵(暗号化用)を渡す
  3. サーバで、公開鍵とユーザを結びつける
  4. サーバは、クライアントがログインしてきたら、乱数を生成して公開鍵で暗号化して渡す
  5. クライアントは、乱数を復号してハッシュ値をサーバに渡する
  6. サーバは、クライアントから来たハッシュ値と、自前のハッシュ値を比較して一致したら認証する


これで、鍵ペアがあればパスワードが無くても認証が可能

具体的な手順(OpenSSHの場合)

クライアント側


鍵ペアの生成

# rsa, dsa は暗号化の方式
$ ssh-keygen -t rsa -C "コメント"
$ ssh-keygen -t dsa -C "コメント"


rsaで作った場合に生成される鍵
秘密鍵: ~/.ssh/id_rsa
公開鍵: ~/.ssh/id_rsa.pub

サーバ側


ログインしたいサーバに公開鍵を追加する

$ cd ~/.ssh
$ cat id_rsa.pub >> authorized_keys
  • authorized_keys は、信頼している公開鍵の一覧


サーバ側の公開鍵のフィンガープリントをメモしておく

$ ssh-keygen -l
Enter file in which the key is (/Users/xxxxxxxx/.ssh/id_rsa): /Users/xxxxxxxx/.ssh/id_rsa.pub
2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx /users/xxxxxxxx/.ssh/id_rsa.pub (RSA)
クライアント側


ssh を使ってログイン

ssh user@server_name


初回ログイン時に、公開鍵のフィンガープリントの確認が出るので、上記でメモしたフィンガープリントと一致していることを確認
同一のipアドレスでサーバを偽装している場合、フィンガープリントが異なるはず

The authenticity of host 'server_name (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
Are you sure you want to continue connecting (yes/no)?


yesを入力すると、~/.ssh/known_host にフィンガープリントが保存されて、
以降、フィンガープリントが異なると警告を出すようになる

参考


入門OpenSSH / 第3章 OpenSSH のしくみ


そんなかんじー