hirura/hrr_rb_ssh

View on GitHub
lib/hrr_rb_ssh/transport/kex_algorithms/elliptic_curve_diffie_hellman.rb

Summary

Maintainability
A
1 hr
Test Coverage
module HrrRbSsh
  class Transport
    class KexAlgorithms
      module EllipticCurveDiffieHellman
        include Loggable
        include IvComputable

        def initialize logger: nil
          self.logger = logger
          @dh = OpenSSL::PKey::EC.new(self.class::CURVE_NAME)
          @dh.generate_key
          @public_key = @dh.public_key.to_bn.to_i
        end

        def start transport
          case transport.mode
          when Mode::SERVER
            @k_s = transport.server_host_key_algorithm.server_public_host_key
            @q_s = @public_key
            message = receive_kexecdh_init transport.receive
            @q_c = message[:'Q_C']
            @shared_secret = OpenSSL::BN.new(@dh.dh_compute_key(OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(self.class::CURVE_NAME).group, OpenSSL::BN.new(@q_c))), 2).to_i
            send_kexecdh_reply transport
          when Mode::CLIENT
            @q_c = @public_key
            send_kexecdh_init transport
            message = receive_kexecdh_reply transport.receive
            @k_s = message[:'K_S']
            @q_s = message[:'Q_S']
            @shared_secret = OpenSSL::BN.new(@dh.dh_compute_key(OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(self.class::CURVE_NAME).group, OpenSSL::BN.new(@q_s))), 2).to_i
          end
        end

        def shared_secret
          @shared_secret
        end

        def hash transport
          h0_payload = {
            :'V_C' => transport.v_c,
            :'V_S' => transport.v_s,
            :'I_C' => transport.i_c,
            :'I_S' => transport.i_s,
            :'K_S' => @k_s,
            :'Q_C' => @q_c,
            :'Q_S' => @q_s,
            :'K'   => @shared_secret,
          }
          h0 = H0.new(logger: logger).encode h0_payload
          h  = OpenSSL::Digest.digest self.class::DIGEST, h0
        end

        def sign transport
          h = hash transport
          s = transport.server_host_key_algorithm.sign h
        end

        def receive_kexecdh_init payload
          Messages::SSH_MSG_KEXECDH_INIT.new(logger: logger).decode payload
        end

        def send_kexecdh_reply transport
          message = {
            :'message number' => Messages::SSH_MSG_KEXECDH_REPLY::VALUE,
            :'K_S'            => @k_s,
            :'Q_S'            => @q_s,
            :'signature of H' => sign(transport),
          }
          payload = Messages::SSH_MSG_KEXECDH_REPLY.new(logger: logger).encode message
          transport.send payload
        end

        def send_kexecdh_init transport
          message = {
            :'message number' => Messages::SSH_MSG_KEXECDH_INIT::VALUE,
            :'Q_C'            => @q_c,
          }
          payload = Messages::SSH_MSG_KEXECDH_INIT.new(logger: logger).encode message
          transport.send payload
        end

        def receive_kexecdh_reply payload
          Messages::SSH_MSG_KEXECDH_REPLY.new(logger: logger).decode payload
        end
      end
    end
  end
end

require 'hrr_rb_ssh/transport/kex_algorithms/elliptic_curve_diffie_hellman/h0'