何をするのか?
Rubyを用いてTCP, TLS通信を行います。
Wiresharkを使って、パケットを確認し、その挙動の違いを観察します。
また、RSAのprivate keyを用いてdecryptionしたりして、理解を深めます。
なぜやろうと思ったのか?
「HTTPS(HTTP over SSL/TLS)をWiresharkで確認する」
みたいな記事はよく拝見しましたが、TLS単体を確認する感じのものは比較的少ないようだったのでやってみました。
コードは以下に置いています。
流れとしては以下の形で進めます。
- Directoryの確認
- TCP
- TLS(over TCP)
Directory
TCP
使用するコードを紹介します。
require "socket"
# open 8081
socket = TCPSocket.open("127.0.0.1", 8081)
# send strings
socket.write("Hello from client")
# close socket
socket.close
require "socket"
# open 8081
server = TCPServer.open(8081)
# connect to client
socket = server.accept
# show strings send by client
while line = socket.gets
puts line
end
# close socket
socket.close
# close server
server.close
clientからserverに文字列を送るプログラムです。
これを実行してみましょう。
以下の順で実行してみてください。
ruby tcp/server.rb
ruby tcp/client.rb
ここでNo.5のパケットを見るとデータが生で送られていることが分かります。
TLS(over TCP)
それでは、TLSに移りましょう。
使用するコードを紹介します。
require 'openssl'
key = OpenSSL::PKey::RSA.new(2048)
# output private key
File.open(__dir__ + "/keys/private_key.pem", "w+") do |f|
f.write(key.export)
end
# output public key
public_key = key.public_key
File.open(__dir__ + "/keys/public_key.pem", "w+") do |f|
f.write(public_key.export)
end
require 'socket'
require 'openssl'
# open 4433
tcp_socket = TCPSocket.new('127.0.0.1', 4433)
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket)
ssl_socket.connect
# send strings
ssl_socket.puts("Hello from client")
# show strings send by server
puts ssl_socket.gets
# close socket
ssl_socket.close
require "socket"
require 'openssl'
# read key
key = OpenSSL::PKey::RSA.new(File.open(__dir__ + "/keys/private_key.pem"))
# create stuff used for TLS
digest = OpenSSL::Digest::SHA1.new()
issuer = subject = OpenSSL::X509::Name.new()
# subject example
subject.add_entry('C', 'JP')
subject.add_entry('ST', 'Tokyo')
subject.add_entry('CN', 'kataokatsuki')
# sign
certification = OpenSSL::X509::Certificate.new()
certification.not_before = Time.at(0)
certification.not_after = Time.at(0)
certification.public_key = key
certification.serial = 1
certification.issuer = issuer
certification.subject = subject
certification.sign(key, digest)
# specify a cipher which use RSA for Kx(Key Exchange) and Au(Authentication)
# you may not decrypt in Wireshark easily if you use ECDHE for Kx
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.cert = certification
ssl_context.key = key
ssl_context.ssl_version = :TLSv1_2
ssl_context.ciphers = ["AES256-GCM-SHA384"]
# open 4433
tcp_server = TCPServer.new('127.0.0.1', 4433)
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
# show strings send by client
socket = ssl_server.accept
text = socket.gets
puts text
# send strings
socket.puts("Server receives a message: " + text)
# close socket
socket.close
# close server
ssl_server.close
clientからserverに文字列を送り, 文字列を送り返すプログラムです。
これを実行してみましょう。
以下の順で実行してみてください。
./tls/keys にpemが作成されます。
ruby tls/create_key.rb
ruby tls/server.rb
ruby tls/client.rb
Wiresharkで確認しましょう。
結構パケットが増えましたね。
きちんとClient Hello出来ていています。
また、「Applicatio Data」を見ると、encryptionされています。
さあ、これからdecriptionしてみましょう。
Preferences > Protocols > TLS
を開いて、「Edit」を押してください。
ここで、「+」を押して各種情報を登録してください。
登録例はこんな形です。
OKを押して反映させましょう。
そうすると、ページ下部に
「Decrypted TLS」
が表示されますので、そちらを表示します。
きちんとdecryptionされていることが分かります。
これにて完了です。お疲れ様でした。
長くなりすぎるので、こちらでは記述をしないのですが、他にもやってて面白かったのはこんなことです。
- session keyを用いてECDHE方式でもdecryptionする
- HTTPを乗せる
- DockerのNGINXイメージを用いてHTTP, HTTPS時のパケットを比較する。
- 様々な暗号方式を比較する
いろいろガチャガチャ触るのは楽しいです。