暗号、SSL、SSH

情報学類 分散システム					2008年02月12日

                                       筑波大学システム情報工学研究科
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2007/2008-02-12
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

■参考文献

■暗号

◆暗号に関する基本用語と安全性

暗号とは、情報の意味が当事者以外にはわからないように情報を変 換することである。

図? 暗号の考え方

図? 暗号の考え方

平文(ひらぶん(clear text))
元の情報
暗号文(cipher text)
変換された情報
平文、暗号文といっても、文字だけでなく、画像や音声などコンピュータが扱 えるあらゆるデータが想定されている。

暗号化(encrypt)
平文を暗号文に変換すること。暗号化鍵が必要。
復号化(decrypt)
暗号文を平文にもどすこと。復号化鍵が必要。
鍵(key)
暗号化や復号化に必要な(短い)データ。
解読
当事者以外の第三者が、暗号文を元にもどすこと、あるいは、復号化鍵を得る こと。
暗号化や復号化の方法(アルゴリズム)は、何種類もある。

◆鍵を使うことの重要性

問: 答え:

暗号化の方法が秘密になっていると、一見、より強そうにみえる。しかし、そ の暗号が、強いのか弱いのか調べる方法がない。攻撃すると、簡単に落ちるか もしれない。暗号化の方法を提供している者が信頼できない時には使えない。

◆長い鍵を使うことの重要性

暗号の安全性は、鍵の安全性によっている。

◆暗号の経済学

暗号の安全は、解読にかかるコストを大きくすることで、解読され た平文から得られる利益を相対的に小さくすることに依存している。

鍵を長くするだけで、安全性が指数関数的に高くなる。 鍵を1ビット長くすると、解読時間が2倍になる。 (「鍵の長さを2倍にすると解読時間が2倍になる」は、誤り)。

図? 指数関数

図? 指数関数

図? 指数関数

図? 指数関数

パスワードは、コンピュータの中では、暗号化の鍵として使われる。 長いパスワードは、破られにくい。1文字(大文字小文字数字記号)増やすと、 総当たりで解読に要する時間が、50倍から100倍近くかかるようになる。

◆共通鍵暗号系と公開鍵暗号系

暗号の方法は、大きく2つに分類される

共通鍵暗号系(対称暗号系)
暗号化鍵と復号化鍵が同じ(または片方から片方が簡単に計算できる)。 DES, 3DES, AES, RC4, 乱数を使うバーナム暗号など。
公開鍵暗号系(非対称暗号系)
暗号化鍵から復号化鍵を容易に類推できない。 RSA, 楕円曲線暗号

◆共通鍵暗号系による暗号通信

同じ鍵で暗号化と復号化を行う。

図? 共通鍵で暗号化

図? 共通鍵暗号系による暗号通信

◆DES

DES(Data Encryption Standard)は、アメリカ商務省標準局(NBS, National Bureau of Standard, 現在のNIST, National Institute of Standrds and Technology)が1977年に定めた暗号標準。 DES は、もはや、安全とは言えない。

3DES (triple DES) は、DES を3重に適応したもの。

DES は、Unix のパスワードのハッシュ関数として使われている。

◆AES

Advanced Encryption Standard。

アメリカ NIST (National Institute of Standards and Technology) が 定めたDES に変わる新しい標準。 全世界に対して公募され、ベルギーのJoan Daemen とVincent Rijmenにより開発されたRijndael方式が採用された。鍵の長さは、 128ビット、192ビット、256ビットから選べる。

◆一方向関数

y=f(x) で、x から y を計算することは簡単だが、y から x 逆を計算するこ とは非常に難しい関数。

◆ハッシュ関数(メッセージ・ダイジェスト)

元データからデータの指紋と呼ぶべきような特徴的な数(普通は元データの長 さによらず固定長)を抽出するもの。

チェックサムや CRC (Cyclic Redundancy Check) にも似ているが、暗号やディ ジタル署名で使われるのは、Collision Proof 性が求められる。

◆暗号によるハッシュ関数の実現

暗号を使えば、一方向関数が作れる(暗号を使わなくても一方向関数を作るこ とはできる)。

one_way_function( x )
{
	return x をキーとして 0 を暗号化したもの ;
}
Unix の /etc/passwd や Apache の htpasswd で遣われているものは、DES を25回繰り返して使って 作ったハッシュ関数の結果。パスワードそのものは、保存されてない。

◆MD2、MD4、MD5

RSA社の B.Kaliski や R.Rivest らによって提案されたメッセージ・ダイジェ ストのアルゴリズム。任意の長さのデータから128ビットのメッセージ・ダイ ジェストを生成する。

◆SHA1 (Secure Hash Algorithm 1)

アメリカの NIST(National Institute of Standards and Technology) が 定めた標準的なメッセージ・ダイジェスト。 出力は、160 ビット。

◆SHA2

SHA-1 の後継。SHA-224, SHA-256, SHA-384, SHA-512 の種類がある。

◆公開鍵暗号系

公開鍵暗号系(非対称暗号系)では2つの異なる鍵を用いる。 便宜上、この2つを公開鍵と秘密鍵と呼ぶ。

これらの鍵は、互いに相手の逆関数になっている。

図? 公開鍵暗号を使った暗号通信の手順

図? 公開鍵暗号を使った暗号通信の手順

  1. 受手は、公開鍵と秘密鍵の組を作り、公開鍵を誰でも読めるようにする。
  2. 送手は、受手の公開鍵を暗号化鍵として用いて暗号文を作り、送る。
  3. 送手は、受け取った暗号文を、自分の秘密鍵を復号化鍵として用いて復号化し、 元の平文を得る。

ここで、公開鍵から秘密鍵を計算することは難しい。ある平文を公開鍵で暗号 化してみたところで、秘密鍵を得ることは難しい。

公開鍵暗号の利点は、鍵を管理する手間が掛らないこと。

共通鍵暗号
情報を交換する間で鍵を安全に共有しなければならない。しかも、通信 相手ごとに鍵を変える必要がある。
公開鍵暗号
受手ごとに、1つの暗号化鍵を公開するだけでよい。今までに通信をしたこと がない人からでも、暗号化されたメッセージを受け取ることが可能である。
公開鍵暗号系は、暗号通信だけでなくディジタル署名や利用者認証、電子現金 にも応用される。

◆RSA

Rivest Shamir Adleman。

RSA暗号は、Rivest, Shamir, Adleman の3人によって開発され た公開鍵暗号系である。RSA暗号の安全性は、大きな数を素因数 分解することの難しさに基づく。北米では、RSAは、2000年 に特許が切れた。

◆楕円曲線暗号

Elliptic Curve Cryptosystem。

公開鍵に基づく暗号化の1つの方法。解読の難しさは、楕円曲線上の離散対数 問題を解くのと同程度と言われている。RSA よりも鍵が短くて高速である。

◆認証

認証とは、情報の正当性や完全性を確保する技術である。

利用者認証
アクセスしてきた人が正当か否かを判定する。 しばしばパスワードや暗唱番号が用いられる。
ディジタル署名(メッセージ認証、電子署名)
通常の署名とおなじく、送られてきたメッセージが送信者本人のもので あることを識別、確認すること。

◆認証の例

◆man-in-the-middle攻撃

いくら暗号通信をしても、通信相手を認証しないと意味がない。 認証しない場合、man-in-the-middle攻撃に弱い。

A=攻撃者、攻撃者=Bで暗号通信

図? man-in-the-middle攻撃

◆ディジタル署名

ディジタル署名では、通常の署名と同様に、次のような性質が必要である。

ディジタル・データでは完全なコピーが簡単に作れるので、紙上の署名や捺印 よりも難しい。

公開鍵暗号系を使ってディジタル署名を行うことができる。

図? 公開鍵暗号を使ったディジタル署名の手順

図? 公開鍵暗号を使ったディジタル署名の手順

  1. (受手ではなく)送手は、公開鍵と秘密鍵の組を作り、公開鍵を誰でも 読めるようにする。
  2. 送手は、自分の秘密鍵を暗号化鍵として用いて暗号文を作り、送る。
  3. 送手は、受け取った暗号文を、送手の秘密鍵を復号化鍵として用いて復 号化し、元の平文を得る。この時、きちんと平文が得られた場合、その平文は、 その公開鍵の持ち主から送られてきたことがわかる。

メッセージ全体を暗号化する代わりに、メッセージを平文で送り、それにメッ セージを一方向関数(ハッシュ関数)と呼ばれる方法で計算した結果だけを、 秘密鍵で暗号化したものを送る方法もある。一方向関数では、計算結果から元 の値(メッセージ)を計算することが難しい。

ディジタル署名や利用者認証は、公開鍵暗号系ではなく、共通鍵暗号系を用い ても可能である。ただし、この場合、鍵を管理する信用できる管理センターが 必要となる。

◆公開鍵暗号を使った利用者認証

サーバへのログインを例に、これを説明する。

  1. ユーザは、サーバにログイン・アカウントを登録する時に、公開鍵と秘 密鍵を生成し、公開鍵をサーバに届け、秘密鍵を自分で保持する。
  2. ユーザは、通信回線を通じてサーバにアクセスしてきた時、サーバは乱 数を1つ生成し、その乱数をユーザの「公開鍵」で暗号化し、ユーザに送り返 す。
  3. ユーザは、送られてきた暗号化された乱数を、保持している秘密鍵で復 号化し、サーバに送り返す。
  4. サーバは、ユーザから返された乱数が正しければ、正当なユーザである と判定する。
次回の呼び出しでは、別の乱数を用いることで、通信を記録している傍受者に も対応することができる(challenge-response方式)。

単なる暗証番号の場合、通信を傍受されたら終り。 毎回違う数を使えば、傍受されていても平気。

◆鍵の確認

公開鍵で自由に鍵が得られたとしても、鍵か偽物だと、意味はない。

鍵がが本物であるかをどうやって確認するか。

では、その第三者は、信頼できるのか。

■SSL(Secure Sockets Layer)

SSL は、Netscape 社によって開発された通信路を暗号化する仕組み。 認証機能もある。 HTTP に広く使われている(他にも使える)。 SSL を IETF により標準化したものが、TLS(Transport Layer Security).

◆3種類認証モデル

良く使われるのは、2番目。 Twins の初期の問題。オレオレ証明書を提示していた。

認証には、証明書が使われる。 鍵の交換にも、証明書に含まれている公開鍵を用いる。

◆証明書

X.509 形式(バイナリ)を、テキストに変換したものの例:

% openssl x509 -text -noout < www.cert[←]
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 225985 (0x372c1)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
        Validity
            Not Before: Mar 13 03:01:02 2006 GMT
            Not After : Mar 13 03:01:02 2010 GMT
        Subject: C=JP, O=www.coins.tsukuba.ac.jp, OU=businessprofile.geotrust.com/get.jsp?GT22591421, OU=See www.rapidssl.com/cps (c)05, OU=Domain Control Validated - RapidSSL(R), CN=www.coins.tsukuba.ac.jp
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:c8:11:30:5b:af:05:2a:22:9d:2a:4e:1d:b7:00:
                    5c:96:70:b4:c3:c1:6d:30:50:d2:5e:1e:0e:87:83:
                    df:5e:b1:ea:c0:98:d8:c5:cd:51:0c:34:3f:74:06:
                    0c:31:e5:9d:5d:b2:cc:b7:e5:2d:d4:c1:33:a0:bc:
                    21:3c:f3:d0:fb:0e:36:95:7f:37:59:1a:41:c3:84:
                    9b:12:3b:6f:39:70:ac:25:b4:4b:30:f6:fa:31:5f:
                    36:64:fd:56:d6:70:60:21:3a:51:0f:39:f8:42:95:
                    09:36:f9:fb:73:db:e7:34:59:c4:96:fa:fa:24:5e:
                    10:af:bc:a9:55:9d:7b:78:9d
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
            X509v3 Subject Key Identifier: 
                DD:FA:B7:F1:41:4A:49:4D:31:BE:87:A1:4A:56:5D:2A:76:CF:E6:E4
            X509v3 CRL Distribution Points: 
                URI:http://crl.geotrust.com/crls/globalca1.crl

            X509v3 Authority Key Identifier: 
                keyid:BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C

            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: md5WithRSAEncryption
        56:1c:4a:f7:e7:a6:16:b0:6d:ed:cf:0c:c9:60:5b:3d:bc:43:
        a5:62:06:13:75:ec:6d:7c:b7:75:cc:0d:f3:02:8f:af:74:90:
        0f:69:8e:28:cc:e5:f8:7f:a2:5d:61:b1:fb:63:3b:31:83:15:
        da:11:c7:ea:62:b2:c9:ad:2e:26:4e:a0:fc:44:a1:16:90:11:
        79:7e:06:c8:23:63:59:7c:09:5f:5b:76:8f:f5:e2:27:66:9c:
        ac:de:ee:49:ee:ea:8b:8c:60:b5:cf:00:52:0b:9b:fa:be:5e:
        c2:8c:02:79:cd:55:c1:d9:04:8c:d1:e4:f7:bc:44:95:80:a7:
        4d:3b
% []

◆認証局の階層

証明書がついていたとして、それが本物であるかをどうやって確認するか。

認証局(CA, Certificate Authority)に、証明書を発行してもらう。(認証局の 秘密鍵でディジタル署名をしてもらう)

その認証局は、信頼できるか?

WWWブラウザには、ルート認証局の証明書が予め含まれている。

末端のWWWサイトは、ルート認証局、または、中間認証局から発行された証 明書を提示する。

ブラウザ、ルート認証局、中間認証局、末端の証明書。ルートは自己署名。

図? ルート認証局から始まる証明書のチェーン

◆ハンドシェーク

接続時に、乱数(共通鍵暗号に基づく暗号化の鍵を生成するため)を交換する。 その乱数は、普通、サーバ側が提示した証明書に含まれている公開鍵で暗号化 される。

ハンドシェークで使われる公開鍵暗号系

データを暗号化するために使われる共通鍵暗号系

◆openssl コマンドによる SSL 付き Apache との対話

WWW ページ https://www.coins.tsukuba.ac.jp/~yas/ を、openssl コマンドを使って得る。
% openssl s_client -connect www.coins.tsukuba.ac.jp:443 -state[←]
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=0 /C=JP/O=www.coins.tsukuba.ac.jp/OU=businessprofile.geotrust.com/get.jsp?GT22591421/OU=See www.rapidssl.com/cps (c)05/OU=Domain Control Validated - RapidSSL(R)/CN=www.coins.tsukuba.ac.jp
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 /C=JP/O=www.coins.tsukuba.ac.jp/OU=businessprofile.geotrust.com/get.jsp?GT22591421/OU=See www.rapidssl.com/cps (c)05/OU=Domain Control Validated - RapidSSL(R)/CN=www.coins.tsukuba.ac.jp
verify error:num=27:certificate not trusted
verify return:1
depth=0 /C=JP/O=www.coins.tsukuba.ac.jp/OU=businessprofile.geotrust.com/get.jsp?GT22591421/OU=See www.rapidssl.com/cps (c)05/OU=Domain Control Validated - RapidSSL(R)/CN=www.coins.tsukuba.ac.jp
verify error:num=21:unable to verify the first certificate
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:SSLv3 read finished A
---
Certificate chain
 0 s:/C=JP/O=www.coins.tsukuba.ac.jp/OU=businessprofile.geotrust.com/get.jsp?GT22591421/OU=See www.rapidssl.com/cps (c)05/OU=Domain Control Validated - RapidSSL(R)/CN=www.coins.tsukuba.ac.jp
   i:/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDdjCCAt+gAwIBAgIDA3LBMA0GCSqGSIb3DQEBBAUAMFoxCzAJBgNVBAYTAlVT
MRwwGgYDVQQKExNFcXVpZmF4IFNlY3VyZSBJbmMuMS0wKwYDVQQDEyRFcXVpZmF4
IFNlY3VyZSBHbG9iYWwgZUJ1c2luZXNzIENBLTEwHhcNMDYwMzEzMDMwMTAyWhcN
MTAwMzEzMDMwMTAyWjCB5TELMAkGA1UEBhMCSlAxIDAeBgNVBAoTF3d3dy5jb2lu
cy50c3VrdWJhLmFjLmpwMTgwNgYDVQQLEy9idXNpbmVzc3Byb2ZpbGUuZ2VvdHJ1
c3QuY29tL2dldC5qc3A/R1QyMjU5MTQyMTEnMCUGA1UECxMeU2VlIHd3dy5yYXBp
ZHNzbC5jb20vY3BzIChjKTA1MS8wLQYDVQQLEyZEb21haW4gQ29udHJvbCBWYWxp
ZGF0ZWQgLSBSYXBpZFNTTChSKTEgMB4GA1UEAxMXd3d3LmNvaW5zLnRzdWt1YmEu
YWMuanAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMgRMFuvBSoinSpOHbcA
XJZwtMPBbTBQ0l4eDoeD316x6sCY2MXNUQw0P3QGDDHlnV2yzLflLdTBM6C8ITzz
0PsONpV/N1kaQcOEmxI7bzlwrCW0SzD2+jFfNmT9VtZwYCE6UQ85+EKVCTb5+3Pb
5zRZxJb6+iReEK+8qVWde3idAgMBAAGjgb0wgbowDgYDVR0PAQH/BAQDAgTwMB0G
A1UdDgQWBBTd+rfxQUpJTTG+h6FKVl0qds/m5DA7BgNVHR8ENDAyMDCgLqAshipo
dHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL2dsb2JhbGNhMS5jcmwwHwYDVR0j
BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEEBQADgYEAVhxK9+em
FrBt7c8MyWBbPbxDpWIGE3XsbXy3dcwN8wKPr3SQD2mOKMzl+H+iXWGx+2M7MYMV
2hHH6mKyya0uJk6g/EShFpAReX4GyCNjWXwJX1t2j/XiJ2acrN7uSe7qi4xgtc8A
Ugub+r5ewowCec1VwdkEjNHk97xElYCnTTs=
-----END CERTIFICATE-----
subject=/C=JP/O=www.coins.tsukuba.ac.jp/OU=businessprofile.geotrust.com/get.jsp?GT22591421/OU=See www.rapidssl.com/cps (c)05/OU=Domain Control Validated - RapidSSL(R)/CN=www.coins.tsukuba.ac.jp
issuer=/C=US/O=Equifax Secure Inc./CN=Equifax Secure Global eBusiness CA-1
---
No client certificate CA names sent
---
SSL handshake has read 1454 bytes and written 346 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 1024 bit
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: C2650B43AB80321774D4D2F1FD5D9F99E0D8D4CD800A30606A9F4D78C4A91F23
    Session-ID-ctx: 
    Master-Key: 87062FBA603CA854BEB83F247B4E8354583E5A6D8015CBFB7074245D759CC45E021B60B1E50CD0FF64764231ECF72301
    Key-Arg   : None
    Start Time: 1202708507
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
GET /~yas/ HTTP/1.0[←]
[←]
HTTP/1.1 200 OK
Date: Mon, 11 Feb 2008 05:42:00 GMT
Server: Apache/2.0.55 (Unix) DAV/2 mod_ssl/2.0.55 OpenSSL/0.9.7d PHP/4.4.2
Last-Modified: Mon, 11 Feb 2008 05:37:19 GMT
ETag: "f86e3f0-1f9-555aa1c0"
Accept-Ranges: bytes
Content-Length: 505
Connection: close
Content-Type: text/html
Content-Language: ja

<HTML>
<HEAD>
<TITLE> SHINJO,Yasushi / Secure WWW
</TITLE>
</HEAD>

<BODY>

<H1>内容</H1>

<UL>
<LI> <A HREF="coins-admin/2003/d/tiki.cgi">coins-admin 用 Tiki (2003)</A>
<LI> <A HREF="j03/d/tiki.cgi">情報学類2003年度入学生のための Tiki (2003)</A>
<LI> <A HREF="coins/dsys-2007/report.cgi">分散システムレポート提出 (2007)</A>
</UL>

<HR>
 <BR>
<ADDRESS> <A HREF="http://www.is.tsukuba.ac.jp/~yas/">Yasushi Shinjo</A> / &lt;yas@is.tsukuba.ac.jp&gt; </ADDRESS>
</BODY>
</HTML>
SSL3 alert read:warning:close notify
closed
SSL3 alert write:warning:close notify
% []

◆SSLの実装

OpenSSL は、SSL 以外の暗合のプログラムも含んでいる。

◆プログラミング(in Java)

Socket, ServerSocket の代りに SSLSocket, SSLServerSocket を使う。 keytool で秘密鍵と証明書を作り、鍵置き場に保存する(CAなしでやる時)。

◆クライアント

   1:	
   2:	/*
   3:	        SSLEchoClient.java -- 文字列を送受信するクライアント(SSL版)
   4:	        ~yas/syspro/ipc/SSLEchoClient.java
   5:	        Created on 2004/02/14 21:09:17
   6:	*/
   7:	
   8:	import java.net.*;
   9:	import java.io.*;
  10:	import javax.net.*;
  11:	import javax.net.ssl.*;
  12:	
  13:	class SSLEchoClient
  14:	{
  15:	    public static void main(String argv[]) throws IOException {
  16:	        if( argv.length != 2 )
  17:	        {
  18:	            System.err.println("Usage: % java SSLEchoClient host port");
  19:	            System.exit( -1 );
  20:	        }
  21:	        String server = argv[0];
  22:	        int portno = Integer.parseInt( argv[1] );
  23:	        echo_client( server, portno );
  24:	    }
  25:	    public static void echo_client( String server, int portno )
  26:	        throws IOException
  27:	    {
  28:	        Socket sock = makeSSLClientSocket( server, portno );
  29:	        BufferedReader in = new BufferedReader(
  30:	            new InputStreamReader( sock.getInputStream() ));
  31:	        PrintStream out = new PrintStream( sock.getOutputStream() );
  32:	        stdout.print("==> ");
  33:	        String sline;
  34:	        while( (sline = stdin.readLine())!= null )
  35:	        {
  36:	            stdout.println("sending: ["+sline +"]");
  37:	            out.println( sline );
  38:	            String rline = in.readLine();
  39:	            stdout.println("received: ["+rline+"]");
  40:	            stdout.print("==> ");
  41:	        }
  42:	        stdout.println("");
  43:	        in.close();
  44:	        out.close();
  45:	        sock.close();
  46:	    }
  47:	    static SSLSocket makeSSLClientSocket( String server, int portno )
  48:	        throws java.io.IOException
  49:	    {
  50:	        SSLSocket ss;
  51:	        SSLSocketFactory ssf = (SSLSocketFactory)SSLSocketFactory.getDefault();
  52:	        Socket s = new Socket( server, portno );
  53:	        ss = (SSLSocket) ssf.createSocket(s,server,portno,true);
  54:	        return( ss );
  55:	    }
  56:	    static java.io.BufferedReader stdin = 
  57:	        new java.io.BufferedReader( new java.io.InputStreamReader(System.in) );
  58:	    static java.io.PrintStream stdout = System.out;
  59:	    static java.io.PrintStream stderr = System.err;     
  60:	}
通常の Socket 版と違う所は、makeSSLClientSocket() だけ。
% diff  EchoClient.java SSLEchoClient.java [←]
3,4c3,4
<       EchoClient.java -- 文字列を送受信するクライアント(TCP/IP版)
<       ~yas/syspro/ipc/EchoClient.java
---
>       SSLEchoClient.java -- 文字列を送受信するクライアント(SSL版)
>       ~yas/syspro/ipc/SSLEchoClient.java
9a10,11
> import javax.net.*;
> import javax.net.ssl.*;
11c13
< class EchoClient
---
> class SSLEchoClient
16c18
<           System.err.println("Usage: % java EchoClient host port");
---
>           System.err.println("Usage: % java SSLEchoClient host port");
23d24
< 
27c28
<       Socket sock = new Socket( server, portno );
---
>       Socket sock = makeSSLClientSocket( server, portno );
45a47,55
>     static SSLSocket makeSSLClientSocket( String server, int portno )
>       throws java.io.IOException
>     {
>       SSLSocket ss;
>       SSLSocketFactory ssf = (SSLSocketFactory)SSLSocketFactory.getDefault();
>       Socket s = new Socket( server, portno );
>       ss = (SSLSocket) ssf.createSocket(s,server,portno,true);
>       return( ss );
>     }
50d59
< 
% []

◆サーバ(Java)

   1:	/*
   2:	        SSLEchoServer.java -- 文字列を送受信するサーバ(SSL版)
   3:	        ~yas/syspro/ipc/SSLEchoServer.java
   4:	        Created on 2004/02/14 16:22:13
   5:	*/
   6:	
   7:	import java.net.*;
   8:	import java.io.*;
   9:	import javax.net.ssl.*;
  10:	
  11:	class SSLEchoServer
  12:	{
  13:	    public static void main(String argv[]) throws IOException {
  14:	        if( argv.length != 1 )
  15:	        {
  16:	            System.err.println("Usage: % java SSLEchoServer port");
  17:	            System.exit( -1 );
  18:	        }
  19:	        int portno = Integer.parseInt( argv[0] );
  20:	        echo_server( portno );
  21:	    }
  22:	
  23:	    public static void echo_server( int portno ) throws IOException
  24:	    {
  25:	        ServerSocket acc = makeSSLServerSocket( portno );
  26:	        print_my_host_port( portno );
  27:	        while( true )
  28:	        {
  29:	            Socket com = acc.accept();
  30:	            tcp_peeraddr_print( com );
  31:	            Thread th = new Thread( new EchoServerWorker(com) );
  32:	            th.start();
  33:	        }
  34:	    }
  35:	    public static void print_my_host_port( int portno ) throws UnknownHostException
  36:	    {
  37:	        InetAddress ia = java.net.InetAddress.getLocalHost();
  38:	        String hostname = ia.getHostName();
  39:	        stdout.println("run openssl s_client -host "+hostname+" -port "+portno );
  40:	    }
  41:	    public static void tcp_peeraddr_print( Socket com )
  42:	    {
  43:	        InetSocketAddress isa = (InetSocketAddress)com.getRemoteSocketAddress();
  44:	        InetAddress ia = isa.getAddress();
  45:	        String peerhostaddr = ia.getHostAddress();
  46:	        int peerportno = isa.getPort();
  47:	        stdout.println("connection (hash=="+com.hashCode()+") from "+peerhostaddr+":"+peerportno );
  48:	    }
  49:	    static SSLServerSocket makeSSLServerSocket(int portno)
  50:	        throws java.io.IOException
  51:	    {
  52:	        SSLServerSocket ss;
  53:	        SSLServerSocketFactory ssf = (SSLServerSocketFactory)
  54:	            SSLServerSocketFactory.getDefault();
  55:	        ss = (SSLServerSocket) ssf.createServerSocket(portno);
  56:	        return( ss );
  57:	    }
  58:	    static java.io.BufferedReader stdin = 
  59:	        new java.io.BufferedReader( new java.io.InputStreamReader(System.in) );
  60:	    static java.io.PrintStream stdout = System.out;
  61:	    static java.io.PrintStream stderr = System.err;     
  62:	}
% diff EchoServer.java SSLEchoServer.java  [←]
2,3c2,3
<       EchoServer.java -- 文字列を送受信するサーバ(TCP/IP, Java版)
<       ~yas/syspro/ipc/EchoServer.java
---
>       SSLEchoServer.java -- 文字列を送受信するサーバ(SSL版)
>       ~yas/syspro/ipc/SSLEchoServer.java
8a9
> import javax.net.ssl.*;
10c11
< class EchoServer
---
> class SSLEchoServer
15c16
<           System.err.println("Usage: % java EchoServer port");
---
>           System.err.println("Usage: % java SSLEchoServer port");
24c25
<       ServerSocket acc = new ServerSocket( portno );
---
>       ServerSocket acc = makeSSLServerSocket( portno );
38c39
<       stdout.println("run telnet "+hostname+" "+portno );
---
>       stdout.println("run openssl s_client -host "+hostname+" -port "+portno );
47a49,57
>     static SSLServerSocket makeSSLServerSocket(int portno)
>       throws java.io.IOException
>     {
>       SSLServerSocket ss;
>       SSLServerSocketFactory ssf = (SSLServerSocketFactory)
>           SSLServerSocketFactory.getDefault();
>       ss = (SSLServerSocket) ssf.createServerSocket(portno);
>       return( ss );
>     }
% []

◆keytoolによる秘密鍵と証明書の生成

% ls -l ./echo.keystore [←]
ls: ./echo.keystore: No such file or directory
% keytool -genkey -keystore ./echo.keystore -storepass "open sesame" -alias echo -keypass "open sesame" [←]
姓名を入力してください。
  [Unknown]:  Yasushi Shinjo[←]
組織単位名を入力してください。
  [Unknown]:  Colleage of Information Science[←]
組織名を入力してください。
  [Unknown]:  University of Tsukuba[←]
都市名または地域名を入力してください。
  [Unknown]:  Tsukuba[←]
州名または地方名を入力してください。
  [Unknown]:  Ibaraki[←]
この単位に該当する 2 文字の国番号を入力してください。
  [Unknown]:  JP[←]
CN=Yasushi Shinjo, OU=Colleage of Information Science, O=University of Tsukuba, L=Tsukuba, ST=Ibaraki, C=JP でよろしいですか?
  [no]:  yes[←]

% ls -l echo.keystore [←]
-rw-r--r--   1 yas  prof  1336 Feb 11 14:51 echo.keystore
% keytool -list -keystore ./echo.keystore [←]
キーストアのパスワードを入力してください:  [←]

  警告 警告 警告  *****************
  キーストアに保存された情報の完全性は検証されて  *
  いません!  完全性を検証するには、キーストアの   *
  パスワードを入力する必要があります。            *
  警告 警告 警告  *****************

キーストアのタイプ: jks
キーストアのプロバイダ: SUN

キーストアには 1 エントリが含まれます。

echo, 2007/02/12, keyEntry,
証明書のフィンガープリント (MD5): B5:56:B9:43:3E:6D:81:5D:3D:99:BB:8E:3A:26:CF:BA
% []
keytool -genkey で、秘密鍵と公開鍵の組が作られる。秘密鍵は、暗号化され る。公開鍵は、X509証明書の形で保存される。公開鍵は、暗号化は行われてい ない。keytool -list でパスワードを与えなくても表示される。

◆サーバの実行

サーバを実行する時には、秘密鍵を含む keyStore と秘密鍵を解くためのパス ワードを与える。
% javac -encoding EUC-JP SSLEchoServer.java  [←]
% java SSLEchoServer [←]
Usage: % java SSLEchoServer port
% java -Djavax.net.ssl.keyStore=./echo.keystore -Djavax.net.ssl.key
StorePassword="open sesame" SSLEchoServer 1231[←]
run openssl s_client -host azalea20.coins.tsukuba.ac.jp -port 1231
connection (hash==10969598) from 127.0.0.1:61688
received (hash==10969598) 12 characters, [The 1st line]
received (hash==10969598) 12 characters, [The 2nd line]
received (hash==10969598) 3 characters, [bye]
connection (hash==10969598) closed.
^C
% []
サーバは自動的には停止しないので、最後は^Cで止める。 ポート番号としては、適当に外の人とぶつからないものを与える。

◆クライアントの実行

クライアントを実行する時には、証明書を含んだ trustStore のファイルを指 定する。SSL で接続する時、サーバがこのファイルに含まれてる公開鍵と同じ ものを提示した時には、信用する。keystore に対するパスワードは不用である。
% javac -encoding EUC-JP SSLEchoClient.java [←]
% java -Djavax.net.ssl.trustStore=./echo.keystore SSLEchoClient loc
alhost 1231[←]
==> The 1st line[←]
sending: [The 1st line]
received: [The 1st line]
==> The 2nd line[←]
sending: [The 2nd line]
received: [The 2nd line]
==> bye[←]
sending: [bye]
received: [bye]
==> ^D[←]
% []
クライアント側は、keystore 全体は不用である。公開鍵を含む証明書だけが あればよい。正式な方法は、keystore ファイルから keytool -export で証明 書を取り出し、別の keystore ファイルに -import で取り込むことである。 しかし、秘密鍵は暗号化されてるので、上のように秘密鍵を含んだままの keystore のファイルをコピーして与る方法もある。

◆プログラミング(in C)

Socket で書かれたプログラムを簡単に SSL 対応に書き換えられる。

Socket 版

/* Returns the number of characters successfully written */
  size_t write(int file_descriptor, void *buf, size_t len)
OpenSSL 版
  /* Returns the number of characters successfully written */
  int SSL_write(SSL *socket_info, char *buf, int len)
実際には、秘密鍵や証明書の設定がめんどくさい。 stunnel を利用する方法もある。

■SSH (Secure Shell)

Unix r系コマンドの置き換え。 トンネリング。暗号化された通信路を作り、その中を他の通信プロトコルを通 す。

◆r系コマンドの弱点

IP spoofing (なりすまし).

rsh のセッションで行われるであろうパケットを偽造する。

IP アドレスでホストを認証すると危ない。

DNS spoofing.

偽のDNSのサーバを立てる。

◆SSHでの解決方法

ホストの認証を、IP アドレスではなく、公開鍵で行う。

サーバは、2つの鍵と64ビットの乱数を送る。 クライアントは、乱数を送り返す。 乱数が一致したら、IP spoofing されていない。

クライアントは、セッション鍵(対称暗号系の鍵)をサーバの2つの公開鍵で 暗号化して送る。

対象暗号の鍵(セッション鍵)を生成し、公開鍵で送る。

これ以降の通信は、セッション鍵で暗号化される。

◆SSHでのユーザの認証

暗号化された通信絽が確立された後は、パスワードを流しても安全。

個人ごとに公開鍵での認証機能を利用したほうがよい。

◆トンネリング(port forwarding)

SSH で暗号化された通信路の中に一般のアプリケーションの通信を通す。 SSH 用語では、port forwarding という。

よくつかわれるもの。

使い方:

% cat bin/ssh-coins-mail [←]
#!/bin/sh
host=mail.coins.tsukuba.ac.jp
ssh -L 10143:$host':'143 -L 10110:$host':'110 -L 10025:$host':'25 $host $*
% []

自分自身(localhostが便利)のポート番号10143, 10110, 10025 に来た接続要 求を、リモートの host の143, 110, 25 に転送する。ssh の接続先(最後の $host)と、-L で指定するホストは必ずしも一致していなくてもよい。 ssh コマンドは、Unix、MacOSX、Cygwin で使える。Windows の TeraTerm や PuTTY でも使える。

図 ssh によるトンネリング(SMTP)

図 ssh によるトンネリング(SMTP)

以下は、上のコマンドを実行して作成したトンネルを使って、SMTP で coins のメール・サーバへアクセスした様子である。
% telnet localhost 10025 [←]
Connected to localhost.
Escape character is '^]'.
220 orchid-nwc.coins.tsukuba.ac.jp ESMTP Postfix
helo azalea20.coins.tsukuba.ac.jp[←]
250 orchid-nwc.coins.tsukuba.ac.jp
quit[←]
221 Bye
Connection closed by foreign host.
% []

◆SSH1の弱点

SSH1 には、プロトコル上、いくつかの弱点が見つかっている。

SSH2 を使った方がよい。

RSA社が提唱している公開鍵を使ってセッション鍵(秘密鍵)を交換する 方式(PKCS1 1.5 )そのものに、脆弱性がある [1]。

PKCS -- Public-Key Cryptography Standards

[1] Daniel Bleichenbacher, "Chosen ciphertext attacks on RSA encryption standard PKCS #1", Advances in Cryptology, CRYPTO 98. Springer.

サーバ鍵を1時間に1回しか変えない。

SSH 1.5 は、1024 ビットの鍵を使っている。 これを破るには、2 20 + 2 19 回接続でよい。毎 秒、約 400 回。

1個所からの接続に上限を付ける。OpenSSH はそうなっている。 Distributed 攻撃には、弱そう。

OpenSSH
http://www.openssh.org/

◆sshにおける公開鍵による認証

SSH では、公開鍵暗号を使った利用者認証 が使える。

準備

利用

Unix のパスワードを利用する方法と比較した時の利点

◆ssh-agentの利用

ssh-agent を使えば、ログイン時には、パスフレーズを打たないでログインで きるようになる。
% ssh-agent tcsh [←]
% printenv SSH_AUTH_SOCK  [←]
% ssh-add -l [←]
		ssh-agentが有効なこと確認
% ssh-add [←]
                鍵の登録
% ssh-add -l [←]
	        鍵が登録されたことの確認
% ssh remote1 [←]
% ssh remote2 [←]
% ssh remote3 [←]
                利用
% exit [←]
                ssh-agentが有効な tcsh の終了
% []
ssh-agent にコマンド(上の例ではtcsh)を与える代りに、csh の環境変数を設 定させるコマンドを出力させ、eval で実行する方法もある。
% eval `ssh-agent` [←]
% printenv SSH_AUTH_SOCK [←]
<以下同じ>
ただし、この方法では、ssh-agent のプロセスが残ってしまう。ssh-agent の 実行を .login などに入れる時には、.logout で ssh-agent -k を実行し、殺 すようにする。


Last updated: 2008/02/12 13:24:39
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>