🧅

SSL 通信を簡単な例で説明してみる

6 min read

はじめに

マスタリングTCP/IP SSL/TLS編で 1.7 章でシンプルなセキュアメッセージシステムという解説があった。理解度を深めるため、それについてまとめてみた。

概要

今回は Alice から Bob に安全にメッセージを送ることを考える。
下記に暗号化の流れ。復号は逆のことをすれば良い。
黄色いところが Bob に送信されるものである。

graph TB
    A[メッセージ] -->|ダイジェストを求める| B[メッセージのダイジェスト値]
    B -->|Alice の秘密鍵でダイジェストの署名| C[メッセージダイジェストの署名]
    A --> D
    B --> E
    C --> F
    subgraph S[共通鍵で暗号化]
    D[メッセージ]
    E[メッセージのダイジェスト値]
    F[メッセージダイジェストの署名]
    end
    subgraph S2[Bob の公開鍵で暗号化]
    G[共通鍵]
    end

(もっとグラフを上手く使いたい人生だった...)

実際の暗号化通信

今回使うもの

共通鍵によるメッセージの暗号化

シーザー暗号を使う。
シーザー暗号とは、指定された数字分(今回は0から255の間)ずらすというものである。
今回は文字を ASCII の数値化したものを3桁ずつ区切って各々鍵を足していく。

例)
鍵: 35
平文: 121117105
暗号文: 156152140

解説)
平文を3桁ずつ区切ると、
121, 117, 105
となり、各々 35 を足すと、
156, 152, 140
となる。
復号は逆のことをすればいい。

メッセージのダイジェスト関数

よくあるのが MD5 やSHA256 などがあるが、今回は簡単にするため独自のものを使う。
3桁ごとで区切っていきその和の 256 の剰余を取ったものとする。

例)
メッセージ: 121117105
ダイジェスト: 87

解説)
メッセージを3桁ごとに区切って足して 256 の剰余をとる。
121 + 117 + 105 = 343 = 256 * 1 + 87

公開鍵

今回は RSA 暗号を使う。手計算でできる桁数とする。

例)
暗号化したい数値: 35
公開鍵: n = 437, e = 17
秘密鍵: p = 19, q = 23, e = 17, d = 233
暗号化したもの: 437

解説)
公開鍵 n = 437 と e = 17 を使うと、
35^17 mod 437 = 101
となるので 101 に暗号化される。
計算結果

それを復号することを考える。復号には秘密鍵 d = 233 が必要である(※)。
101^233 mod 437 = 35
より復号できる。
計算結果

※正確にいうと n = 437 を素因数分解することによっても復号ができるが、現実的な時間でできないという仮定のもと RSA の安全性が担保されているので、できないとしている

電子署名

これも RSA 暗号を使う。さっきは公開鍵 n, e の値を使ったが、電子署名は n, d の値を使う。
つまり e の役割と d の役割が入れ替えて使う。

実演

"yakiniku" という文字列(ASCII で表現すると "121097107105110105107117")を Alice が Bob に送信することを考える。

Alice がやること

Bob から公開鍵を受け取る

公開鍵: n = 437, e = 17

メッセージダイジェストの計算

メッセージのダイジェストを求める。
121 + 097 + 107 + 105 + 110 + 105 + 107 + 117 = 869 = 256 * 3 + 101
より 101 となる。

ダイジェスト値の署名

Alice が下記の RSA の鍵を用意する。

公開鍵: n = 667, e = 17
秘密鍵: p = 23, q = 29, e = 17, d = 145

ダイジェスト値 101 を秘密鍵で署名する。
101^145 mod 667 を計算すると 541 となる。
計算結果

Bob の公開鍵で共通鍵を暗号化

Bob から受け取った公開鍵 n = 437, e = 17 で、共通鍵 35 を暗号化する。

35^17 mod 437 = 101
より 101 に暗号化される(この計算は上の例で計算済み)。

共通鍵での暗号化

メッセージと証明書と署名を暗号化する。
共通鍵として 35 を用意。

メッセージの "yakiniku"
"121097107105110105107117" を3桁ずつ区切って 35 を足していくと "156132142140145140142152" になる。

証明書(公開鍵)の "n=667,e=17"
そのまま ASCII にすると "110061054054055044101061049055" を3桁ずつ区切って 35 を足していくと "145096089089090079136096084090" になる。

署名の "541"
そのまま ASCII にすると "053052049" を3桁ずつ区切って 35 を足していくと "088087084" になる。

Alice が Bob に送信するもの

156132142140145140142152
145096089089090079136096084090
088087084
101

上からそれぞれ、

  • メッセージを暗号化したもの
  • Alice の公開鍵を暗号化したもの
  • ダイジェストの署名を暗号化したもの
  • 共通鍵を Bob の公開鍵で暗号化したもの

となっている。

メッセージを受け取った Bob がやること

受け取ったメッセージ

156132142140145140142152
145096089089090079136096084090
088087084
101

暗号化された共通鍵を復号する

101 を Bob の秘密鍵で復号する。
101^233 mod 437 = 35
より 35 に復号される(この計算は上の例で計算済み)。

共通鍵で暗号化されたものを復号する

156132142140145140142152
145096089089090079136096084090
088087084
これらから 35 を引く。

121097107105110105107117 ("yakiniku")
110061054054055044101061049055 ("n=667,e=17")
053052049 ("541")
であることがわかる。

メッセージが改竄されていないか検証をする

"121097107105110105107117" からダイジェストを求めると 101 になる。
ダイジェストの署名 541 と Alice の公開鍵から復号すると、
541^17 mod 667 = 101
計算結果

なので、署名されたメッセージダイジェストから得られた値と同じになるため、メッセージが改竄されていないことがわかる。

安全性を担保するための仮定

Bob から受け取った公開鍵が本当に Bob であるということ

Alice が Bob から受け取った公開鍵 n = 437, e = 17 が本当に Bob から受け取ったものであることが必須である。さもなくば man-in-the-middle 攻撃ができてしまう。

man-in-the-middle 攻撃とは、攻撃者 Jack が Alice と Bob の通信の間に入って、 Bob が Alice に渡そうとしていた公開鍵を Jack が用意した公開鍵に差し替え、それを Alice に渡す。

graph LR
    Bob -->|Bob の公開鍵| Jack 
    Jack -->|Jack の公開鍵| Alice

Alice が Jack の公開鍵で暗号化したものを Jack が受け取り、 Jack の秘密鍵で復号し Bob の公開鍵で暗号化して Bob に送信する。

graph LR
    Alice -->|Jack の公開鍵で暗号化| Jack 
    Jack -->|Bob の公開鍵で暗号化| Bob
    Jack -->|復号 & 暗号化| Jack

そうすることによって、 Alice と Bob に気づかれることなく盗聴することができる。

共通鍵によるメッセージの暗号化が破られないこと

今回、メッセージ "yakiniku" をシーザー暗号で暗号化した。
鍵がなくても復号されないことを仮定している。

ただ、シーザー暗号は総当たり攻撃で簡単に破ることが簡単である。今回の場合、 0 から 255 まで試せばいい。
※シーザー暗号ということを伏せておけばいいのではないか、という考えもあるが、暗号化アルゴリズムを隠すことによって安全を担保するのはあまりいい方法ではない

ここで注意して欲しいのは、この共通鍵によるメッセージだけが破られただけなら、機密性が破られただけで、メッセージ完全性は破られていない。つまり、メッセージの改竄はできないということである(メッセージダイジェストと電子署名で検知できる)。

公開鍵暗号が破られないこと

今回採用した公開鍵暗号の RSA が安全としている理由は素因数分解が難しいことを使っている。
今回は暗号化で使う Bob の鍵と、電子署名で使う Alice の鍵がある。両方とも n が素因数分解されることによって破られる。

試しに、 Bob の公開鍵で暗号化された共通鍵を解読してみる。
つまり、 Bob の公開鍵 n = 437, e = 17 によって暗号化された 101 を復号する。
437 を素因数分解すると 19 * 23 であるので、
17^(-1) mod (19 - 1)(23 - 1) = 233
計算結果

よって d = 233 となるので、
101^233 mod 437 = 35
計算結果
となり復号できた。

この公開鍵が破られても機密性が破られただけで、メッセージ完全性は破られていない。

電子署名が破られないこと

今回は電子署名にも RSA を使っているので、上記と同じことが言える。
ここでの電子署名はメッセージのダイジェストの正当性を示すために使っている。

先ほど、共通鍵による暗号化が破られた場合でも、メッセージの完全性が破られていないという話をしたが、同時にこの電子署名が破られるとそのメッセージ完全性も担保できなくなる。なので攻撃者 Jack がメッセージの改竄ができるようになる。

実際に Jack がやることを見ていく。
共通鍵が破られたとすると、メッセージと署名されたダイジェストがわかる。
メッセージ: yakiniku
ダイジェストの署名: 541

そこで、メッセージを "tamanegi" に変えて、ダイジェストとその署名を求めると、
改竄したメッセージ: tamanegi
ダイジェストの署名: 70
となる。

なので、それらを共通鍵で暗号化して下記のものに差し替えることによって、メッセージの改竄ができる(Bob からしたら改竄されたことに気づけない)。
151132144132145136138140
090083

Bob が「何食べたい?」と聞いて Alice が「たまねぎ」と言ってきたことになる。

ダイジェスト関数が衝突しないこと

衝突といってもいくつか種類がある。今回は、原像計算困難性のことを指す。上記で準備したダイジェスト関数は原像計算は容易い。つまり(第一)原像攻撃が簡単である。

原像攻撃とは、与えられたダイジェスト値 h に対して、ダイジェスト値が h となるメッセージ m を探すことである。

graph LR
    メッセージ -->|ダイジェスト関数| H[h] 
    m -->|ダイジェスト関数| H

今回で言うと、ダイジェスト値が 101 となるメッセージを探し出すことであり、その一例として "e" ととれる(もっといい例あっただろ)。
なので、電子署名が破られていなくても、原像攻撃ができればメッセージの改竄が可能である。ただ、ダイジェスト値が固定されているのでその分自由度は減る。
(今回の場合は、メッセージの改竄をするには共通鍵の解読をしていないといけない)。

安全性のまとめ

今回のシステムについてまとめてみた。

機密性 メッセージ完全性
Bob の公開鍵が偽物 x △ Alice の公開鍵の真正性による
共通鍵が破られた x o
Bob の公開鍵が破られた x o
(共通鍵が破られ)電子署名が破られた x x
(共通鍵が破られ)ダイジェスト関数が破られた x x

今回はシーザー暗号や桁数の少ない RSA 暗号など簡単に破れるものを使ったが、実際に使われているものは、(今の技術では)そう簡単に破られることはない。

Discussion

ログインするとコメントできます