Class: Noise::State::HandshakeState
- Inherits:
-
Object
- Object
- Noise::State::HandshakeState
- Defined in:
- lib/noise/state/handshake_state.rb
Overview
A HandshakeState object contains a SymmetricState plus the following variables, any of which may be empty. Empty is a special value which indicates the variable has not yet been initialized.
s: The local static key pair e: The local ephemeral key pair rs: The remote party's static public key re: The remote party's ephemeral public key
A HandshakeState also has variables to track its role, and the remaining portion of the handshake pattern:
initiator: A boolean indicating the initiator or responder role.
message_patterns: A sequence of message patterns. Each message pattern is a sequence of tokens from the set ("e", "s", "ee", "es", "se", "ss").
Instance Attribute Summary collapse
-
#e ⇒ Object
readonly
Returns the value of attribute e.
-
#message_patterns ⇒ Object
readonly
Returns the value of attribute message_patterns.
-
#re ⇒ Object
readonly
Returns the value of attribute re.
-
#rs ⇒ Object
readonly
Returns the value of attribute rs.
-
#s ⇒ Object
readonly
Returns the value of attribute s.
-
#symmetric_state ⇒ Object
readonly
Returns the value of attribute symmetric_state.
Instance Method Summary collapse
- #expected_message_length(payload_size) ⇒ Object
- #get_keypair_getter(initiator) ⇒ Object
-
#initialize(connection, initiator, prologue, local_keypairs, remote_keys) ⇒ HandshakeState
constructor
A new instance of HandshakeState.
- #local_keypair_getter ⇒ Object
- #process_fallback(initiator_keypair_getter) ⇒ Object
- #process_initiator_pre_messages(keypair_getter) ⇒ Object
- #process_responder_pre_messages(keypair_getter) ⇒ Object
-
#read_message(message, payload_buffer) ⇒ Boolean
Takes a byte sequence containing a Noise handshake message, and a payload_buffer to write the message's plaintext payload into.
- #remote_keypair_getter ⇒ Object
-
#write_message(payload, message_buffer) ⇒ Boolean
Takes a payload byte sequence which may be zero-length, and a message_buffer to write the output into.
Constructor Details
#initialize(connection, initiator, prologue, local_keypairs, remote_keys) ⇒ HandshakeState
Returns a new instance of HandshakeState.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/noise/state/handshake_state.rb', line 22 def initialize(connection, initiator, prologue, local_keypairs, remote_keys) @connection = connection @protocol = connection.protocol @symmetric_state = SymmetricState.initialize_symmetric(@protocol, connection, prologue: prologue) @initiator = initiator @s = local_keypairs[:s] @e = local_keypairs[:e] @rs = remote_keys[:rs] @re = remote_keys[:re] initiator_keypair_getter, responder_keypair_getter = get_keypair_getter(initiator) # Sets message_patterns to the message patterns from handshake_pattern. The inner arrays are # copied too, so consuming them here can never reach back into the shared Pattern. @message_patterns = @protocol.pattern.tokens.map(&:dup) (initiator_keypair_getter) process_fallback(initiator_keypair_getter) (responder_keypair_getter) end |
Instance Attribute Details
#e ⇒ Object (readonly)
Returns the value of attribute e.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def e @e end |
#message_patterns ⇒ Object (readonly)
Returns the value of attribute message_patterns.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def @message_patterns end |
#re ⇒ Object (readonly)
Returns the value of attribute re.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def re @re end |
#rs ⇒ Object (readonly)
Returns the value of attribute rs.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def rs @rs end |
#s ⇒ Object (readonly)
Returns the value of attribute s.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def s @s end |
#symmetric_state ⇒ Object (readonly)
Returns the value of attribute symmetric_state.
20 21 22 |
# File 'lib/noise/state/handshake_state.rb', line 20 def symmetric_state @symmetric_state end |
Instance Method Details
#expected_message_length(payload_size) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/noise/state/handshake_state.rb', line 81 def (payload_size) has_key = @symmetric_state.cipher_state.key? pattern = @message_patterns.first len = pattern.inject(0) do |l, token| case token when Noise::Token::E l += @protocol.dh_fn.dhlen has_key = true if @protocol.psk? when Noise::Token::S l += @protocol.dh_fn.dhlen l += 16 if has_key else has_key = true end l end len += payload_size len += 16 if has_key len end |
#get_keypair_getter(initiator) ⇒ Object
43 44 45 46 47 48 49 |
# File 'lib/noise/state/handshake_state.rb', line 43 def get_keypair_getter(initiator) if initiator [local_keypair_getter, remote_keypair_getter] else [remote_keypair_getter, local_keypair_getter] end end |
#local_keypair_getter ⇒ Object
51 52 53 |
# File 'lib/noise/state/handshake_state.rb', line 51 def local_keypair_getter ->(token) { instance_variable_get("@#{token}").public_key } end |
#process_fallback(initiator_keypair_getter) ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/noise/state/handshake_state.rb', line 66 def process_fallback(initiator_keypair_getter) return unless @protocol.pattern.fallback = @message_patterns.delete_at(0).first public_key = initiator_keypair_getter.call() @symmetric_state.mix_hash(public_key) end |
#process_initiator_pre_messages(keypair_getter) ⇒ Object
59 60 61 62 63 64 |
# File 'lib/noise/state/handshake_state.rb', line 59 def (keypair_getter) @protocol.pattern.&.map do |token| keypair = keypair_getter.call(token) @symmetric_state.mix_hash(keypair) end end |
#process_responder_pre_messages(keypair_getter) ⇒ Object
74 75 76 77 78 79 |
# File 'lib/noise/state/handshake_state.rb', line 74 def (keypair_getter) @protocol.pattern.&.map do |token| keypair = keypair_getter.call(token) @symmetric_state.mix_hash(keypair) end end |
#read_message(message, payload_buffer) ⇒ Boolean
Takes a byte sequence containing a Noise handshake message, and a payload_buffer to write the message's plaintext payload into
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/noise/state/handshake_state.rb', line 134 def (, payload_buffer) pattern = @message_patterns.shift pattern.each do |token| case token when Noise::Token::E , @re = extract_key(, false) mix_e(@re) when Noise::Token::S , @rs = extract_key(, true) when Noise::Token::EE, Noise::Token::ES, Noise::Token::SE, Noise::Token::SS token.mix(@symmetric_state, @protocol.dh_fn, @initiator, self) when Noise::Token::PSK mix_psk end end payload_buffer << @symmetric_state.decrypt_and_hash() finish_handshake end |
#remote_keypair_getter ⇒ Object
55 56 57 |
# File 'lib/noise/state/handshake_state.rb', line 55 def remote_keypair_getter ->(token) { instance_variable_get("@r#{token}") } end |
#write_message(payload, message_buffer) ⇒ Boolean
Takes a payload byte sequence which may be zero-length, and a message_buffer to write the output into
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/noise/state/handshake_state.rb', line 104 def (payload, ) pattern = @message_patterns.shift pattern.each do |token| case token when Noise::Token::E # A fresh keypair per handshake is what the pattern's forward secrecy rests on. Two # things preset @e. Connection::Base#fallback carries the ephemeral of the aborted # handshake into the new state, which the fallback patterns require: process_fallback # mixes its public key as a pre-message. A caller passing keypairs[:e] to # Connection::Base#initialize also presets it, and that is supported for reproducing # the official test vectors and nothing else. @e ||= @protocol.dh_fn.generate_keypair << @e.public_key mix_e(@e.public_key) when Noise::Token::S << @symmetric_state.encrypt_and_hash(@s.public_key) when Noise::Token::EE, Noise::Token::ES, Noise::Token::SE, Noise::Token::SS token.mix(@symmetric_state, @protocol.dh_fn, @initiator, self) when Noise::Token::PSK mix_psk end end << @symmetric_state.encrypt_and_hash(payload) finish_handshake end |