Class: CryptoToolchain::DiffieHellman::Peer

Inherits:
Object
  • Object
show all
Defined in:
lib/crypto_toolchain/diffie_hellman/peer.rb

Direct Known Subclasses

MITM

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(debug: false, name: SecureRandom.uuid, p: NIST_P, g: NIST_G) ⇒ Peer

Returns a new instance of Peer.



4
5
6
7
8
9
10
11
12
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 4

def initialize(debug: false, name: SecureRandom.uuid, p: NIST_P, g: NIST_G)
  @addresses = {}
  @channel = Queue.new
  @name = name
  @debug = debug
  @p = p
  @g = g
  @received_messages = []
end

Instance Attribute Details

#addressesObject (readonly)

Returns the value of attribute addresses.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def addresses
  @addresses
end

#channelObject (readonly)

Returns the value of attribute channel.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def channel
  @channel
end

#debugObject (readonly) Also known as: debug?

Returns the value of attribute debug.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def debug
  @debug
end

#gObject (readonly)

Returns the value of attribute g.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def g
  @g
end

#nameObject (readonly)

Returns the value of attribute name.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def name
  @name
end

#pObject (readonly)

Returns the value of attribute p.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def p
  @p
end

#received_messagesObject (readonly)

Returns the value of attribute received_messages.



126
127
128
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 126

def received_messages
  @received_messages
end

Instance Method Details

#add_address(peer) ⇒ Object



38
39
40
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 38

def add_address(peer)
  @addresses[peer.name] ||= PeerInfo.new(peer: peer, channel: peer.channel )
end

#datum_response(msg) ⇒ Object



68
69
70
71
72
73
74
75
76
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 68

def datum_response(msg)
  data = msg.decrypt(key: info_for(msg.peer).session_key)
  puts "#{name} got message containing #{data} from #{msg.peer.name}" if debug
  if msg.initial?
    encrypted = encrypted_message_for(msg.peer, message: data, initial: false)
    send_msg(msg.peer, encrypted)
  end
  @received_messages << ReceivedMessage.new(from: msg.peer.name, contents: data)
end

#die_response(msg) ⇒ Object

Raises:



34
35
36
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 34

def die_response(msg)
  raise ReceivedDie
end

#encrypted_message_for(peer, message:, initial: false) ⇒ Object



111
112
113
114
115
116
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 111

def encrypted_message_for(peer, message: , initial: false)
  key = info_for(peer).session_key
  iv = Random.new.bytes(16)
  encrypted = (iv + message.encrypt_cbc(key: key, iv: iv))
  Messages::Datum.new(peer: self, contents: encrypted, initial: initial)
end

#info_for(peer) ⇒ Object



92
93
94
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 92

def info_for(peer)
  addresses.fetch(peer.name)
end

#invalid_pubkey?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 122

def invalid_pubkey?
  !valid_pubkey?
end

#key_exchange_response(msg) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 50

def key_exchange_response(msg)
  info = info_for(msg.peer)
  if msg.initial?
    @p = msg.p
    @g = msg.g
  end
  info.update(p: p, g: g, pubkey: msg.pubkey)
  info.set_shared_secret(privkey)
  if debug
    puts "#{name} will use p = #{p}"
    puts "#{name} will use g = #{g}"
    puts "#{name} thinks #{msg.peer.name} has pubkey #{msg.pubkey}"
    puts "#{name} generated secret #{info.shared_secret} for #{msg.peer.name}"
  end
  my_pubkey_msg = Messages::KeyExchange.new(peer: self, pubkey: pubkey, initial: false)
  send_msg msg.peer, my_pubkey_msg if msg.initial?
end

#my_address_message(initial: false) ⇒ Object



107
108
109
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 107

def my_address_message(initial: false)
  Messages::PeerAddress.new(peer: self, channel: self.channel, initial: initial)
end

#peer_address_response(msg) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 42

def peer_address_response(msg)
  add_address(msg.peer)
  if msg.initial?
    send_msg msg.peer, my_address_message
  end
  puts "#{name} added #{msg.peer.name}" if debug
end

#privkeyObject

Raises:

  • (RuntimeError)


102
103
104
105
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 102

def privkey
  raise RuntimeError.new("Can't generate private key until p has been set") if p.nil?
  @privkey ||= rand(1..0xffffffff) % p
end

#process!Object Also known as: process



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 14

def process!
  when_ready do
    msg = channel.pop
    message_type = msg.class.to_s.split(':').last
    if msg.respond_to?(:peer)
      puts "#{name} got #{message_type} from #{msg.peer.name}" if debug
    end
    method = "#{message_type}_response".snakecase
    unless self.respond_to?(method)
      raise ArgumentError.new("Don't know how to process method :#{method}")
    end
    begin
      send(method, msg)
    rescue ReceivedDie
      break
    end
  end
end

#pubkeyObject

Raises:

  • (RuntimeError)


96
97
98
99
100
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 96

def pubkey
  raise RuntimeError.new("Can't generate public key until p has been set") if p.nil?
  raise RuntimeError.new("Can't generate public key until g has been set") if g.nil?
  @pubkey ||= g.modexp(privkey, p)
end

#send_msg(peer, message) ⇒ Object



87
88
89
90
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 87

def send_msg(peer, message)
  puts "#{name} sends #{message.class.to_s.split(':').last} to #{peer.name}" if debug
  peer.channel.enq(message)
end

#valid_pubkey?Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 118

def valid_pubkey?
  pubkey < p
end

#when_readyObject



78
79
80
81
82
83
84
85
# File 'lib/crypto_toolchain/diffie_hellman/peer.rb', line 78

def when_ready
  loop do
    while(channel.empty?)
      sleep 0.001
    end
    yield
  end
end