サンプルプログラムの実装


https://github.com/haruyama/ssh_client_sample/blob...

  private def exchangeKeys(transportManager: TransportManager, clientVersion: String, serverVersion: String, clientKexinit: Kexinit, serverKexinit: Kexinit) = {

    //ch.ethz.ssh2.crypto.dh.DhExchange を利用して
    //diffie-hellman-group1-sha1 鍵交換法を行なう準備をする
    val dhx = new DhExchange
    dhx.init(1, new SecureRandom);

    // SSH_MSG_KEXDH_INIT メッセージを送信する
    val kexdhInit = DhExchangeMessageBuilder.buildKexdhInit(dhx.getE())
    transportManager.sendMessage(kexdhInit)

    // SSH_MSG_KEYDH_REPLY メッセージを受信する
    val kexDhReply = transportManager.recvMessage().asInstanceOf[KexdhReply]

    // SSH_MSG_KEYDH_REPLY にホスト公開鍵をローカルなデータベースなどで検証し
    // 接続先ホストを認証しなければならない.ここでは省略する

    // 交換ハッシュ H を計算する
    dhx.setF(kexDhReply.f.value)
    val h = dhx.calculateH(clientVersion.getBytes, serverVersion.getBytes, clientKexinit.toBytes,
      serverKexinit.toBytes, kexDhReply.hostKey.value)

    // SSH_MSG_KEYDH_REPLY 中に H の署名がついている.これをホスト公開鍵で検証する
    val rs = RSASHA1Verify.decodeSSHRSASignature(kexDhReply.sigOfH.value)
    val rpk = RSASHA1Verify.decodeSSHRSAPublicKey(kexDhReply.hostKey.value)
    if (!RSASHA1Verify.verifySignature(h, rs, rpk)) new RuntimeException("RSA Key is not verified")

    // 交換ハッシュ H と 共有の秘密 K を返す
    (h, dhx.getK)
  }

解説


Diffie-Hellman 鍵交換を行ないます. Diffie-Hellman の実装は Ganymed SSH-2 for Java を利用しています.
この鍵交換では, 交換ハッシュ H と共有の秘密 K が交換されます.

共有の秘密 K は, Diffie-Hellman 鍵交換により計算されます.
交換ハッシュ H は, バージョン文字列, SSH_MSG_KEXINIT メッセージ, サーバのホスト公開鍵, Diffie-Hellman 鍵交換でやりとりされる値 を連結したもののハッシュです.

以上の2つから, 暗号化のための鍵とIV, MACのための鍵を計算します.

SSH_MSG_KEXDH_INIT の送信


鍵交換のために, e と呼ばれる値を生成しこれを SSH_MSG_KEXDH_INIT メッセージで送信します.

byte      SSH_MSG_KEXDH_INIT
mpint     e

SSH_MSG_KEYDH_REPLY の受信


応答として SSH_MSG_KEYDH_REPLY がサーバから送られてきます.

byte      SSH_MSG_KEXDH_REPLY
string    server public host key and certificates (K_S)
mpint     f
string    signature of H
  • server public host key and certificates (K_S)
    • サーバホスト公開鍵
  • f
    • Diffie-Hellman 鍵交換で利用する値
  • signature of H
    • サーバの秘密鍵による H の署名

サーバホスト公開鍵の検証



クライアントは, サーバホスト公開鍵をローカルなデータベースなどによって検証します. OpenSSH では ~/.ssh/known_hosts にサーバ名と公開鍵のセットが登録されているか検索します. 登録されていなかったりサーバ名に対する公開鍵が異なる場合は警告を出します. この警告を無視すると, クライアントが本来接続したいサーバではない接続する可能性があります.

サンプルプログラムでは, この検証は省略しています.

交換ハッシュ H と 共有の秘密 K の計算


共有の秘密 K は Diffie-Hellman 鍵交換の結果計算されます.
交換ハッシュ H は, バージョン文字列, SSH_MSG_KEXINIT メッセージ, サーバのホスト公開鍵, Diffie-Hellman 鍵交換でやりとりされる値 をハッシュ(この場合はsha1)化して計算されます.

交換ハッシュ H に対する署名の検証


交換ハッシュ H に対する署名が SSH_MSG_KEYDH_REPLY に含まれています. これを検証し, サーバがホスト公開鍵に対応する秘密鍵を持っていることを検証します.

交換ハッシュ H と 共有の秘密 K の返却


暗号化のための鍵とIV, MACのための鍵の計算に必要なので, 交換ハッシュ H と 共有の秘密 K をタプルで返却します.

メンバーのみ編集できます