noise-ruby 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +47 -1
 - data/bin/console +2 -0
 - data/lib/noise.rb +1 -0
 - data/lib/noise/connection.rb +4 -89
 - data/lib/noise/connection/base.rb +112 -0
 - data/lib/noise/connection/initiator.rb +22 -0
 - data/lib/noise/connection/responder.rb +22 -0
 - data/lib/noise/functions/cipher/cha_cha_poly.rb +2 -2
 - data/lib/noise/functions/dh/ed25519.rb +2 -6
 - data/lib/noise/functions/dh/ed448.rb +3 -6
 - data/lib/noise/functions/dh/secp256k1.rb +4 -9
 - data/lib/noise/functions/hash/blake2s.rb +25 -25
 - data/lib/noise/key.rb +12 -0
 - data/lib/noise/protocol.rb +3 -72
 - data/lib/noise/state/cipher_state.rb +4 -0
 - data/lib/noise/state/handshake_state.rb +35 -46
 - data/lib/noise/state/symmetric_state.rb +30 -21
 - data/lib/noise/version.rb +1 -1
 - metadata +6 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 9fcf6ecf59b631aacb32b66661719e57a205ccea71a487748d3bb2979fc2ee4b
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 22bee13bda1fe1a9339777261eccd6d173e32679e969e78b065abe457d06884e
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 2cbd93529da1345b646b9be626591bf81eb1fe53d211d70a75fe6fe1f56d99c7b55bdedc7102aed3d20c27080fcf4f04b0619b7bacd8f664f8301397f3f4e069
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: '0845488f8a48edb3f09fba247a8f7950aefd0c5a6cade1ae114e3b3e683e4f66dbc3d34267b2ee298f066d170ddd84343da3d843a5a89587ce592cac906da849'
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -49,7 +49,53 @@ gem 'secp256k1-ruby' 
     | 
|
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
            ## Usage
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
      
 52 
     | 
    
         
            +
            Followings shows handshake protocol with "Noise_NN_25519_ChaChaPoly_BLAKE2b"
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            ### Handshake
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            #### initiator
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            ```
         
     | 
| 
      
 59 
     | 
    
         
            +
            initiator = Noise::Connection::Initiator.new("Noise_NN_25519_ChaChaPoly_BLAKE2b")
         
     | 
| 
      
 60 
     | 
    
         
            +
            initiator.prologue = "test" # => "test"
         
     | 
| 
      
 61 
     | 
    
         
            +
            initiator.start_handshake # => true
         
     | 
| 
      
 62 
     | 
    
         
            +
            cipher = initiator.write_message("") # => "\xB6\xF7gmxi\xAB\xBCY|t\xF0\x9D\x01A\ad\x92\xBBvp\x80ZNU\f=\x83\x81^\xFD\x15"
         
     | 
| 
      
 63 
     | 
    
         
            +
            ```
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            then initiator sends `cipher` to responder.
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            #### responder
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            Responder receive `cipher` from initiator.
         
     | 
| 
      
 70 
     | 
    
         
            +
            Responder respond messages to initiator.
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            ```
         
     | 
| 
      
 73 
     | 
    
         
            +
            responder = Noise::Connection::Responder.new("Noise_NN_25519_ChaChaPoly_BLAKE2b")
         
     | 
| 
      
 74 
     | 
    
         
            +
            responder.prologue = "test" # => "test"
         
     | 
| 
      
 75 
     | 
    
         
            +
            responder.start_handshake # => true
         
     | 
| 
      
 76 
     | 
    
         
            +
            plain = responder.read_message(cipher) # => ""
         
     | 
| 
      
 77 
     | 
    
         
            +
            cipher = responder.write_message("") # => "\v\xD9\x97'\xC0\xB1\xC9\xFFD\x8C\x7F\x18L\xB0\xF2\x14\xB0\x11\xC0\x90\xAAZ\xE1\x03\x17z)\xB81/5L\x16\xE3\xD1\xBE<{\xB8\xBB\xD6\xF1\x00\x10]\x99=\xD7"
         
     | 
| 
      
 78 
     | 
    
         
            +
            ```
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            ### initiator
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ```
         
     | 
| 
      
 84 
     | 
    
         
            +
            plain = initiator.read_message(cipher) # => ""
         
     | 
| 
      
 85 
     | 
    
         
            +
            ```
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ### Send transport message (after handshake finished)
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            ```
         
     | 
| 
      
 90 
     | 
    
         
            +
            cipher = initiator.encrypt("Hello, World!") # => "\xDA\xC7\xD7as\v\xFA\xCC,\xB3\xC7\xD0/xL\xE8I,\xD9\n\xEExh\x8F\xFA\xD6\x01\x99W"
         
     | 
| 
      
 91 
     | 
    
         
            +
            ```
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            ### Receive transport message
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            ```
         
     | 
| 
      
 96 
     | 
    
         
            +
            plain = responder.decrypt(cipher) # => "Hello, World!"
         
     | 
| 
      
 97 
     | 
    
         
            +
            ```
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
       53 
99 
     | 
    
         | 
| 
       54 
100 
     | 
    
         
             
            ## Development
         
     | 
| 
       55 
101 
     | 
    
         | 
    
        data/bin/console
    CHANGED
    
    
    
        data/lib/noise.rb
    CHANGED
    
    
    
        data/lib/noise/connection.rb
    CHANGED
    
    | 
         @@ -1,94 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Noise
         
     | 
| 
       4 
     | 
    
         
            -
               
     | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  EPHEMERAL = 3
         
     | 
| 
       9 
     | 
    
         
            -
                  REMOTE_EPHEMERAL = 4
         
     | 
| 
       10 
     | 
    
         
            -
                end
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                attr_accessor :protocol, :handshake_started, :handshake_finished, :fn
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                def initialize(name)
         
     | 
| 
       15 
     | 
    
         
            -
                  @protocol = Protocol.create(name)
         
     | 
| 
       16 
     | 
    
         
            -
                  @handshake_started = false
         
     | 
| 
       17 
     | 
    
         
            -
                  @handshake_finished = false
         
     | 
| 
       18 
     | 
    
         
            -
                  @fn = nil
         
     | 
| 
       19 
     | 
    
         
            -
                  @write_message_proc = ->(payload) { write_message(payload) }
         
     | 
| 
       20 
     | 
    
         
            -
                  @read_message_proc = ->(payload) { read_message(payload) }
         
     | 
| 
       21 
     | 
    
         
            -
                end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                def psks=(psks)
         
     | 
| 
       24 
     | 
    
         
            -
                  @protocol.psks = psks
         
     | 
| 
       25 
     | 
    
         
            -
                end
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                def prologue=(prologue)
         
     | 
| 
       28 
     | 
    
         
            -
                  @protocol.prologue = prologue
         
     | 
| 
       29 
     | 
    
         
            -
                end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                def set_as_initiator!
         
     | 
| 
       32 
     | 
    
         
            -
                  @protocol.initiator = true
         
     | 
| 
       33 
     | 
    
         
            -
                  @fn = @write_message_proc
         
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                def set_as_responder!
         
     | 
| 
       37 
     | 
    
         
            -
                  @protocol.initiator = false
         
     | 
| 
       38 
     | 
    
         
            -
                  @fn = @read_message_proc
         
     | 
| 
       39 
     | 
    
         
            -
                end
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                def set_keypair_from_private(keypair, private_key)
         
     | 
| 
       42 
     | 
    
         
            -
                  @protocol.keypairs[keypair.to_sym] = @protocol.dh_fn.class.from_private(private_key)
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                def set_keypair_from_public(keypair, public_key)
         
     | 
| 
       46 
     | 
    
         
            -
                  @protocol.keypairs[keypair.to_sym] = @protocol.dh_fn.class.from_public(public_key)
         
     | 
| 
       47 
     | 
    
         
            -
                end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                def start_handshake
         
     | 
| 
       50 
     | 
    
         
            -
                  @protocol.validate
         
     | 
| 
       51 
     | 
    
         
            -
                  @protocol.initialise_handshake_state
         
     | 
| 
       52 
     | 
    
         
            -
                  @handshake_started = true
         
     | 
| 
       53 
     | 
    
         
            -
                end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                def write_message(payload = '')
         
     | 
| 
       56 
     | 
    
         
            -
                  # Call NoiseConnection.start_handshake first
         
     | 
| 
       57 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError unless @handshake_started
         
     | 
| 
       58 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError if @fn != @write_message_proc
         
     | 
| 
       59 
     | 
    
         
            -
                  # Handshake finished. NoiseConnection.encrypt should be used now
         
     | 
| 
       60 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError if @handshake_finished
         
     | 
| 
       61 
     | 
    
         
            -
                  @fn = @read_message_proc
         
     | 
| 
       62 
     | 
    
         
            -
                  buffer = +''
         
     | 
| 
       63 
     | 
    
         
            -
                  result = @protocol.handshake_state.write_message(payload, buffer)
         
     | 
| 
       64 
     | 
    
         
            -
                  @handshake_finished = true if result
         
     | 
| 
       65 
     | 
    
         
            -
                  buffer
         
     | 
| 
       66 
     | 
    
         
            -
                end
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                def read_message(data)
         
     | 
| 
       69 
     | 
    
         
            -
                  # Call NoiseConnection.start_handshake first
         
     | 
| 
       70 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError unless @handshake_started
         
     | 
| 
       71 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError if @fn != @read_message_proc
         
     | 
| 
       72 
     | 
    
         
            -
                  # Handshake finished. NoiseConnection.encrypt should be used now
         
     | 
| 
       73 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError if @handshake_finished
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                  @fn = @write_message_proc
         
     | 
| 
       76 
     | 
    
         
            -
                  buffer = +''
         
     | 
| 
       77 
     | 
    
         
            -
                  result = @protocol.handshake_state.read_message(data, buffer)
         
     | 
| 
       78 
     | 
    
         
            -
                  @handshake_finished = true if result
         
     | 
| 
       79 
     | 
    
         
            -
                  buffer
         
     | 
| 
       80 
     | 
    
         
            -
                end
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                def encrypt(data)
         
     | 
| 
       83 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError unless @handshake_finished
         
     | 
| 
       84 
     | 
    
         
            -
                  # raise Noise::Exceptions::NoiseInvalidMessage
         
     | 
| 
       85 
     | 
    
         
            -
                  @protocol.cipher_state_encrypt.encrypt_with_ad('', data)
         
     | 
| 
       86 
     | 
    
         
            -
                end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                def decrypt(data)
         
     | 
| 
       89 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseHandshakeError unless @handshake_finished
         
     | 
| 
       90 
     | 
    
         
            -
                  # raise Noise::Exceptions::NoiseInvalidMessage
         
     | 
| 
       91 
     | 
    
         
            -
                  @protocol.cipher_state_decrypt.decrypt_with_ad('', data)
         
     | 
| 
       92 
     | 
    
         
            -
                end
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Connection
         
     | 
| 
      
 5 
     | 
    
         
            +
                autoload :Base, 'noise/connection/base'
         
     | 
| 
      
 6 
     | 
    
         
            +
                autoload :Initiator, 'noise/connection/initiator'
         
     | 
| 
      
 7 
     | 
    
         
            +
                autoload :Responder, 'noise/connection/responder'
         
     | 
| 
       93 
8 
     | 
    
         
             
              end
         
     | 
| 
       94 
9 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Noise
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Connection
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :protocol, :handshake_started, :handshake_finished, :handshake_hash
         
     | 
| 
      
 7 
     | 
    
         
            +
                  attr_reader :cipher_state_encrypt, :cipher_state_decrypt, :cipher_state_handshake
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_accessor :psks, :prologue
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(name, keypairs: { s: nil, e: nil, rs: nil, re: nil })
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @protocol = Protocol.create(name)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    @keypairs = keypairs
         
     | 
| 
      
 14 
     | 
    
         
            +
                    # parameter keypairs[:e] and keypairs[:s] are strings, so should convert Noise::Key object.
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @keypairs[:e] = @protocol.dh_fn.class.from_private(@keypairs[:e]) if @keypairs[:e]
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @keypairs[:s] = @protocol.dh_fn.class.from_private(@keypairs[:s]) if @keypairs[:s]
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    @handshake_started = false
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @handshake_finished = false
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @next_message = nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def start_handshake
         
     | 
| 
      
 24 
     | 
    
         
            +
                    validate
         
     | 
| 
      
 25 
     | 
    
         
            +
                    initialise_handshake_state
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @handshake_started = true
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def initialise_handshake_state
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @handshake_state = Noise::State::HandshakeState.new(
         
     | 
| 
      
 31 
     | 
    
         
            +
                      self,
         
     | 
| 
      
 32 
     | 
    
         
            +
                      protocol,
         
     | 
| 
      
 33 
     | 
    
         
            +
                      initiator?,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      @prologue,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      @keypairs
         
     | 
| 
      
 36 
     | 
    
         
            +
                    )
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @symmetric_state = @handshake_state.symmetric_state
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @cipher_state_handshake = @symmetric_state.cipher_state
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def write_message(payload = '')
         
     | 
| 
      
 42 
     | 
    
         
            +
                    # Call NoiseConnection.start_handshake first
         
     | 
| 
      
 43 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError unless @handshake_started
         
     | 
| 
      
 44 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError if @next_message != :write
         
     | 
| 
      
 45 
     | 
    
         
            +
                    # Handshake finished. NoiseConnection.encrypt should be used now
         
     | 
| 
      
 46 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError if @handshake_finished
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @next_message = :read
         
     | 
| 
      
 48 
     | 
    
         
            +
                    buffer = +''
         
     | 
| 
      
 49 
     | 
    
         
            +
                    result = @handshake_state.write_message(payload, buffer)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @handshake_finished = true if result
         
     | 
| 
      
 51 
     | 
    
         
            +
                    buffer
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  def read_message(data)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    # Call NoiseConnection.start_handshake first
         
     | 
| 
      
 56 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError unless @handshake_started
         
     | 
| 
      
 57 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError if @next_message != :read
         
     | 
| 
      
 58 
     | 
    
         
            +
                    # Handshake finished. NoiseConnection.encrypt should be used now
         
     | 
| 
      
 59 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError if @handshake_finished
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    @next_message = :write
         
     | 
| 
      
 62 
     | 
    
         
            +
                    buffer = +''
         
     | 
| 
      
 63 
     | 
    
         
            +
                    result = @handshake_state.read_message(data, buffer)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    @handshake_finished = true if result
         
     | 
| 
      
 65 
     | 
    
         
            +
                    buffer
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  def encrypt(data)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError unless @handshake_finished
         
     | 
| 
      
 70 
     | 
    
         
            +
                    # raise Noise::Exceptions::NoiseInvalidMessage
         
     | 
| 
      
 71 
     | 
    
         
            +
                    @cipher_state_encrypt.encrypt_with_ad('', data)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def decrypt(data)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseHandshakeError unless @handshake_finished
         
     | 
| 
      
 76 
     | 
    
         
            +
                    # raise Noise::Exceptions::NoiseInvalidMessage
         
     | 
| 
      
 77 
     | 
    
         
            +
                    @cipher_state_decrypt.decrypt_with_ad('', data)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  def validate_psk!
         
     | 
| 
      
 81 
     | 
    
         
            +
                    # Invalid psk length! Has to be 32 bytes long
         
     | 
| 
      
 82 
     | 
    
         
            +
                    raise Noise::Exceptions::NoisePSKError if @psks.any? { |psk| psk.bytesize != 32 }
         
     | 
| 
      
 83 
     | 
    
         
            +
                    # Bad number of PSKs provided to this protocol! {} are required,
         
     | 
| 
      
 84 
     | 
    
         
            +
                    # given {}'.format(self.pattern.psk_count, len(self.psks)))
         
     | 
| 
      
 85 
     | 
    
         
            +
                    raise Noise::Exceptions::NoisePSKError if @protocol.pattern.psk_count != @psks.count
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def valid_keypairs?
         
     | 
| 
      
 89 
     | 
    
         
            +
                    @protocol.pattern.required_keypairs(initiator?).any? { |keypair| !@keypairs[keypair] }
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def validate
         
     | 
| 
      
 93 
     | 
    
         
            +
                    validate_psk! if psk_handshake?
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                    # 'Keypair {} has to be set for chosen handshake pattern'.format(keypair)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    raise Noise::Exceptions::NoiseValidationError if valid_keypairs?
         
     | 
| 
      
 97 
     | 
    
         
            +
                    true
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  def psk_handshake?
         
     | 
| 
      
 101 
     | 
    
         
            +
                    @protocol.is_psk_handshake
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  def handshake_done(_c1, _c2)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    @handshake_hash = @symmetric_state.handshake_hash
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @handshake_state = nil
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @symmetric_state = nil
         
     | 
| 
      
 108 
     | 
    
         
            +
                    @cipher_state_handshake = nil
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Noise
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Connection
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Initiator < Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(name, keypairs: { s: nil, e: nil, rs: nil, re: nil })
         
     | 
| 
      
 7 
     | 
    
         
            +
                    super
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @next_message = :write
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def initiator?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    true
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def handshake_done(c1, c2)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @cipher_state_encrypt = c1
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @cipher_state_decrypt = @protocol.pattern.one_way ? nil : c2
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Noise
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Connection
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Responder < Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(name, keypairs: { s: nil, e: nil, rs: nil, re: nil })
         
     | 
| 
      
 7 
     | 
    
         
            +
                    super
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @next_message = :read
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def initiator?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    false
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def handshake_done(c1, c2)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @cipher_state_decrypt = c1
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @cipher_state_encrypt = @protocol.pattern.one_way ? nil : c2
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,14 +8,14 @@ module Noise 
     | 
|
| 
       8 
8 
     | 
    
         
             
                      @cipher = RbNaCl::AEAD::ChaCha20Poly1305IETF.new(String.new(k).force_encoding('ASCII-8BIT'))
         
     | 
| 
       9 
9 
     | 
    
         
             
                      @cipher.encrypt(nonce_to_bytes(n), plaintext, ad)
         
     | 
| 
       10 
10 
     | 
    
         
             
                    rescue ::RbNaCl::CryptoError => e
         
     | 
| 
       11 
     | 
    
         
            -
                      raise Noise::Exceptions::EncryptError 
     | 
| 
      
 11 
     | 
    
         
            +
                      raise Noise::Exceptions::EncryptError, e
         
     | 
| 
       12 
12 
     | 
    
         
             
                    end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
                    def decrypt(k, n, ad, ciphertext)
         
     | 
| 
       15 
15 
     | 
    
         
             
                      @cipher = RbNaCl::AEAD::ChaCha20Poly1305IETF.new(String.new(k).force_encoding('ASCII-8BIT'))
         
     | 
| 
       16 
16 
     | 
    
         
             
                      @cipher.decrypt(nonce_to_bytes(n), ciphertext, ad)
         
     | 
| 
       17 
17 
     | 
    
         
             
                    rescue ::RbNaCl::CryptoError => e
         
     | 
| 
       18 
     | 
    
         
            -
                      raise Noise::Exceptions::DecryptError 
     | 
| 
      
 18 
     | 
    
         
            +
                      raise Noise::Exceptions::DecryptError, e
         
     | 
| 
       19 
19 
     | 
    
         
             
                    end
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                    def nonce_to_bytes(n)
         
     | 
| 
         @@ -9,7 +9,7 @@ module Noise 
     | 
|
| 
       9 
9 
     | 
    
         
             
                      private_key = 1 + SecureRandom.random_number(RbNaCl::GroupElement::STANDARD_GROUP_ORDER - 1)
         
     | 
| 
       10 
10 
     | 
    
         
             
                      scalar_as_string = ECDSA::Format::IntegerOctetString.encode(private_key, 32)
         
     | 
| 
       11 
11 
     | 
    
         
             
                      public_key = RbNaCl::GroupElements::Curve25519.base.mult(scalar_as_string)
         
     | 
| 
       12 
     | 
    
         
            -
                       
     | 
| 
      
 12 
     | 
    
         
            +
                      Noise::Key.new(ECDSA::Format::IntegerOctetString.encode(private_key, 32), public_key.to_bytes)
         
     | 
| 
       13 
13 
     | 
    
         
             
                    end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                    def dh(private_key, public_key)
         
     | 
| 
         @@ -22,11 +22,7 @@ module Noise 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    def self.from_private(private_key)
         
     | 
| 
       24 
24 
     | 
    
         
             
                      public_key = RbNaCl::GroupElements::Curve25519.base.mult(private_key)
         
     | 
| 
       25 
     | 
    
         
            -
                       
     | 
| 
       26 
     | 
    
         
            -
                    end
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                    def self.from_public(public_key)
         
     | 
| 
       29 
     | 
    
         
            -
                      [nil, public_key]
         
     | 
| 
      
 25 
     | 
    
         
            +
                      Noise::Key.new(private_key, public_key.to_bytes)
         
     | 
| 
       30 
26 
     | 
    
         
             
                    end
         
     | 
| 
       31 
27 
     | 
    
         
             
                  end
         
     | 
| 
       32 
28 
     | 
    
         
             
                end
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Noise
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Functions
         
     | 
| 
       3 
5 
     | 
    
         
             
                module DH
         
     | 
| 
         @@ -7,18 +9,13 @@ module Noise 
     | 
|
| 
       7 
9 
     | 
    
         
             
                      throw NotImplementedError
         
     | 
| 
       8 
10 
     | 
    
         
             
                    end
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                    def dh( 
     | 
| 
      
 12 
     | 
    
         
            +
                    def dh(_key_pair, _public_key)
         
     | 
| 
       11 
13 
     | 
    
         
             
                      throw NotImplementedError
         
     | 
| 
       12 
14 
     | 
    
         
             
                    end
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
16 
     | 
    
         
             
                    def dhlen
         
     | 
| 
       15 
17 
     | 
    
         
             
                      DHLEN
         
     | 
| 
       16 
18 
     | 
    
         
             
                    end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                    def self.from_private(private_key)
         
     | 
| 
       19 
     | 
    
         
            -
                    end
         
     | 
| 
       20 
     | 
    
         
            -
                    def self.from_public(private_key)
         
     | 
| 
       21 
     | 
    
         
            -
                    end
         
     | 
| 
       22 
19 
     | 
    
         
             
                  end
         
     | 
| 
       23 
20 
     | 
    
         
             
                end
         
     | 
| 
       24 
21 
     | 
    
         
             
              end
         
     | 
| 
         @@ -5,7 +5,6 @@ begin 
     | 
|
| 
       5 
5 
     | 
    
         
             
            rescue LoadError
         
     | 
| 
       6 
6 
     | 
    
         
             
            end
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
8 
     | 
    
         
             
            module Noise
         
     | 
| 
       10 
9 
     | 
    
         
             
              module Functions
         
     | 
| 
       11 
10 
     | 
    
         
             
                module DH
         
     | 
| 
         @@ -14,17 +13,17 @@ module Noise 
     | 
|
| 
       14 
13 
     | 
    
         
             
                      group = ECDSA::Group::Secp256k1
         
     | 
| 
       15 
14 
     | 
    
         
             
                      private_key = 1 + SecureRandom.random_number(group.order - 1)
         
     | 
| 
       16 
15 
     | 
    
         
             
                      public_key = group.generator.multiply_by_scalar(private_key)
         
     | 
| 
       17 
     | 
    
         
            -
                       
     | 
| 
      
 16 
     | 
    
         
            +
                      Noise::Key.new(
         
     | 
| 
       18 
17 
     | 
    
         
             
                        ECDSA::Format::IntegerOctetString.encode(private_key, 32),
         
     | 
| 
       19 
18 
     | 
    
         
             
                        ECDSA::Format::PointOctetString.encode(public_key, compression: true)
         
     | 
| 
       20 
     | 
    
         
            -
                       
     | 
| 
      
 19 
     | 
    
         
            +
                      )
         
     | 
| 
       21 
20 
     | 
    
         
             
                    end
         
     | 
| 
       22 
21 
     | 
    
         | 
| 
       23 
22 
     | 
    
         
             
                    def dh(private_key, public_key)
         
     | 
| 
       24 
23 
     | 
    
         
             
                      key = ::Secp256k1::PublicKey.new(pubkey: public_key, raw: true)
         
     | 
| 
       25 
24 
     | 
    
         
             
                      key.ecdh(private_key)
         
     | 
| 
       26 
25 
     | 
    
         
             
                    rescue ::Secp256k1::AssertError => _
         
     | 
| 
       27 
     | 
    
         
            -
                      raise Noise::Exceptions::InvalidPublicKeyError 
     | 
| 
      
 26 
     | 
    
         
            +
                      raise Noise::Exceptions::InvalidPublicKeyError, public_key
         
     | 
| 
       28 
27 
     | 
    
         
             
                    end
         
     | 
| 
       29 
28 
     | 
    
         | 
| 
       30 
29 
     | 
    
         
             
                    def dhlen
         
     | 
| 
         @@ -35,11 +34,7 @@ module Noise 
     | 
|
| 
       35 
34 
     | 
    
         
             
                      group = ECDSA::Group::Secp256k1
         
     | 
| 
       36 
35 
     | 
    
         
             
                      scalar = ECDSA::Format::IntegerOctetString.decode(private_key)
         
     | 
| 
       37 
36 
     | 
    
         
             
                      point = group.generator.multiply_by_scalar(scalar)
         
     | 
| 
       38 
     | 
    
         
            -
                       
     | 
| 
       39 
     | 
    
         
            -
                    end
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    def self.from_public(public_key)
         
     | 
| 
       42 
     | 
    
         
            -
                      [nil, public_key]
         
     | 
| 
      
 37 
     | 
    
         
            +
                      Noise::Key.new(private_key, ECDSA::Format::PointOctetString.encode(point, compression: true))
         
     | 
| 
       43 
38 
     | 
    
         
             
                    end
         
     | 
| 
       44 
39 
     | 
    
         
             
                  end
         
     | 
| 
       45 
40 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,46 +27,46 @@ module Noise 
     | 
|
| 
       27 
27 
     | 
    
         
             
                  end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                  class Blake2sDigester
         
     | 
| 
       30 
     | 
    
         
            -
                    IV = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    IV = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19].freeze
         
     | 
| 
       31 
31 
     | 
    
         
             
                    SIGMA = [
         
     | 
| 
       32 
     | 
    
         
            -
                      [ 
     | 
| 
       33 
     | 
    
         
            -
                      [ 
     | 
| 
       34 
     | 
    
         
            -
                      [ 
     | 
| 
       35 
     | 
    
         
            -
                      [ 
     | 
| 
       36 
     | 
    
         
            -
                      [ 
     | 
| 
       37 
     | 
    
         
            -
                      [ 
     | 
| 
       38 
     | 
    
         
            -
                      [ 
     | 
| 
       39 
     | 
    
         
            -
                      [ 
     | 
| 
       40 
     | 
    
         
            -
                      [ 
     | 
| 
       41 
     | 
    
         
            -
                      [ 
     | 
| 
       42 
     | 
    
         
            -
                    ]
         
     | 
| 
      
 32 
     | 
    
         
            +
                      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
         
     | 
| 
      
 33 
     | 
    
         
            +
                      [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
         
     | 
| 
      
 34 
     | 
    
         
            +
                      [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
         
     | 
| 
      
 35 
     | 
    
         
            +
                      [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
         
     | 
| 
      
 36 
     | 
    
         
            +
                      [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
         
     | 
| 
      
 37 
     | 
    
         
            +
                      [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
         
     | 
| 
      
 38 
     | 
    
         
            +
                      [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
         
     | 
| 
      
 39 
     | 
    
         
            +
                      [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
         
     | 
| 
      
 40 
     | 
    
         
            +
                      [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
         
     | 
| 
      
 41 
     | 
    
         
            +
                      [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ].freeze
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
44 
     | 
    
         
             
                    def initialize(key: '')
         
     | 
| 
       45 
45 
     | 
    
         
             
                      @key = key
         
     | 
| 
       46 
     | 
    
         
            -
                      @ctx = init(Blake2s::HASHLEN, @key.unpack( 
     | 
| 
      
 46 
     | 
    
         
            +
                      @ctx = init(Blake2s::HASHLEN, @key.unpack('C*'))
         
     | 
| 
       47 
47 
     | 
    
         
             
                    end
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         
             
                    def update(data)
         
     | 
| 
       50 
     | 
    
         
            -
                      update_internal(@ctx, data.unpack( 
     | 
| 
      
 50 
     | 
    
         
            +
                      update_internal(@ctx, data.unpack('C*'))
         
     | 
| 
       51 
51 
     | 
    
         
             
                      self
         
     | 
| 
       52 
52 
     | 
    
         
             
                    end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
54 
     | 
    
         
             
                    def digest
         
     | 
| 
       55 
55 
     | 
    
         
             
                      out = []
         
     | 
| 
       56 
56 
     | 
    
         
             
                      final(@ctx, out)
         
     | 
| 
       57 
     | 
    
         
            -
                      out.pack( 
     | 
| 
      
 57 
     | 
    
         
            +
                      out.pack('C*')
         
     | 
| 
       58 
58 
     | 
    
         
             
                    end
         
     | 
| 
       59 
59 
     | 
    
         | 
| 
       60 
60 
     | 
    
         
             
                    # @return context
         
     | 
| 
       61 
61 
     | 
    
         
             
                    def init(out_len, key)
         
     | 
| 
       62 
     | 
    
         
            -
                      raise ArgumentError if out_len  
     | 
| 
      
 62 
     | 
    
         
            +
                      raise ArgumentError if out_len.zero? || out_len > 32
         
     | 
| 
       63 
63 
     | 
    
         
             
                      h = IV.dup
         
     | 
| 
       64 
64 
     | 
    
         
             
                      h[0] ^= 0x01010000 ^ (key.size << 8) ^ out_len
         
     | 
| 
       65 
65 
     | 
    
         
             
                      t = 0
         
     | 
| 
       66 
66 
     | 
    
         
             
                      c = 0
         
     | 
| 
       67 
67 
     | 
    
         
             
                      b = Array.new(Blake2s::BLOCKLEN).fill(0, key.size)
         
     | 
| 
       68 
68 
     | 
    
         
             
                      ctx = Context.new(b, h, t, c, out_len)
         
     | 
| 
       69 
     | 
    
         
            -
                      if key.size 
     | 
| 
      
 69 
     | 
    
         
            +
                      if key.size.positive?
         
     | 
| 
       70 
70 
     | 
    
         
             
                        update_internal(ctx, key)
         
     | 
| 
       71 
71 
     | 
    
         
             
                        ctx.c = 64
         
     | 
| 
       72 
72 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -101,12 +101,12 @@ module Noise 
     | 
|
| 
       101 
101 
     | 
    
         
             
                    private
         
     | 
| 
       102 
102 
     | 
    
         | 
| 
       103 
103 
     | 
    
         
             
                    def to_int32(x)
         
     | 
| 
       104 
     | 
    
         
            -
                      x  
     | 
| 
      
 104 
     | 
    
         
            +
                      x &= 0xFFFFFFFF
         
     | 
| 
       105 
105 
     | 
    
         
             
                      x < 0x80000000 ? x : x - 2**32
         
     | 
| 
       106 
106 
     | 
    
         
             
                    end
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
                    def rshift(x, y, range=32)
         
     | 
| 
       109 
     | 
    
         
            -
                      (x + (x  
     | 
| 
      
 108 
     | 
    
         
            +
                    def rshift(x, y, range = 32)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      (x + (x.positive? ? 0 : 2**range)) >> y
         
     | 
| 
       110 
110 
     | 
    
         
             
                    end
         
     | 
| 
       111 
111 
     | 
    
         | 
| 
       112 
112 
     | 
    
         
             
                    def rotr32(x, y)
         
     | 
| 
         @@ -151,11 +151,11 @@ module Noise 
     | 
|
| 
       151 
151 
     | 
    
         
             
                      end
         
     | 
| 
       152 
152 
     | 
    
         | 
| 
       153 
153 
     | 
    
         
             
                      10.times do |i|
         
     | 
| 
       154 
     | 
    
         
            -
                        mix_g(v, 0, 4,  8, 12, m[SIGMA[i][ 
     | 
| 
       155 
     | 
    
         
            -
                        mix_g(v, 1, 5,  9, 13, m[SIGMA[i][ 
     | 
| 
       156 
     | 
    
         
            -
                        mix_g(v, 2, 6, 10, 14, m[SIGMA[i][ 
     | 
| 
       157 
     | 
    
         
            -
                        mix_g(v, 3, 7, 11, 15, m[SIGMA[i][ 
     | 
| 
       158 
     | 
    
         
            -
                        mix_g(v, 0, 5, 10, 15, m[SIGMA[i][ 
     | 
| 
      
 154 
     | 
    
         
            +
                        mix_g(v, 0, 4,  8, 12, m[SIGMA[i][0]], m[SIGMA[i][1]])
         
     | 
| 
      
 155 
     | 
    
         
            +
                        mix_g(v, 1, 5,  9, 13, m[SIGMA[i][2]], m[SIGMA[i][3]])
         
     | 
| 
      
 156 
     | 
    
         
            +
                        mix_g(v, 2, 6, 10, 14, m[SIGMA[i][4]], m[SIGMA[i][5]])
         
     | 
| 
      
 157 
     | 
    
         
            +
                        mix_g(v, 3, 7, 11, 15, m[SIGMA[i][6]], m[SIGMA[i][7]])
         
     | 
| 
      
 158 
     | 
    
         
            +
                        mix_g(v, 0, 5, 10, 15, m[SIGMA[i][8]], m[SIGMA[i][9]])
         
     | 
| 
       159 
159 
     | 
    
         
             
                        mix_g(v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]])
         
     | 
| 
       160 
160 
     | 
    
         
             
                        mix_g(v, 2, 7,  8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]])
         
     | 
| 
       161 
161 
     | 
    
         
             
                        mix_g(v, 3, 4,  9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]])
         
     | 
    
        data/lib/noise/key.rb
    ADDED
    
    
    
        data/lib/noise/protocol.rb
    CHANGED
    
    | 
         @@ -2,14 +2,9 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Noise
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Protocol
         
     | 
| 
       5 
     | 
    
         
            -
                attr_accessor : 
     | 
| 
       6 
     | 
    
         
            -
                attr_accessor : 
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
       8 
     | 
    
         
            -
                attr_accessor :psks
         
     | 
| 
       9 
     | 
    
         
            -
                attr_reader :name, :cipher_fn, :hash_fn, :dh_fn, :hkdf_fn, :pattern
         
     | 
| 
       10 
     | 
    
         
            -
                attr_reader :handshake_state, :keypairs, :keypair_fn
         
     | 
| 
       11 
     | 
    
         
            -
                attr_reader :handshake_hash
         
     | 
| 
       12 
     | 
    
         
            -
                attr_accessor :ck
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :is_psk_handshake
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :cipher_fn, :hash_fn, :dh_fn, :hkdf_fn
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :name, :pattern
         
     | 
| 
       13 
8 
     | 
    
         | 
| 
       14 
9 
     | 
    
         
             
                CIPHER = {
         
     | 
| 
       15 
10 
     | 
    
         
             
                  'AESGCM': Noise::Functions::Cipher::AesGcm,
         
     | 
| 
         @@ -38,9 +33,7 @@ module Noise 
     | 
|
| 
       38 
33 
     | 
    
         
             
                def initialize(name, pattern_name, cipher_name, hash_name, dh_name)
         
     | 
| 
       39 
34 
     | 
    
         
             
                  @name = name
         
     | 
| 
       40 
35 
     | 
    
         
             
                  @pattern = Noise::Pattern.create(pattern_name)
         
     | 
| 
       41 
     | 
    
         
            -
                  @keypairs = { s: [], e: [], rs: [], re: [] }
         
     | 
| 
       42 
36 
     | 
    
         
             
                  @hkdf_fn = Noise::Functions::Hash.create_hkdf_fn(hash_name)
         
     | 
| 
       43 
     | 
    
         
            -
                  @psks = []
         
     | 
| 
       44 
37 
     | 
    
         
             
                  @is_psk_handshake = @pattern.modifiers.any? { |m| m.start_with?('psk') }
         
     | 
| 
       45 
38 
     | 
    
         | 
| 
       46 
39 
     | 
    
         
             
                  @pattern.apply_pattern_modifiers
         
     | 
| 
         @@ -55,68 +48,6 @@ module Noise 
     | 
|
| 
       55 
48 
     | 
    
         
             
                  raise Noise::Exceptions::ProtocolNameError unless @cipher_fn && @hash_fn && @dh_fn
         
     | 
| 
       56 
49 
     | 
    
         
             
                end
         
     | 
| 
       57 
50 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                def handshake_done
         
     | 
| 
       59 
     | 
    
         
            -
                  if @pattern.one_way
         
     | 
| 
       60 
     | 
    
         
            -
                    if @initiator
         
     | 
| 
       61 
     | 
    
         
            -
                      @cipher_state_decrypt = nil
         
     | 
| 
       62 
     | 
    
         
            -
                    else
         
     | 
| 
       63 
     | 
    
         
            -
                      @cipher_state_encrypt = nil
         
     | 
| 
       64 
     | 
    
         
            -
                    end
         
     | 
| 
       65 
     | 
    
         
            -
                  end
         
     | 
| 
       66 
     | 
    
         
            -
                  @handshake_hash = @symmetric_state.handshake_hash
         
     | 
| 
       67 
     | 
    
         
            -
                  @keypairs = @handshake_state.keypairs
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                  @handshake_state = nil
         
     | 
| 
       70 
     | 
    
         
            -
                  @ck = @symmetric_state.ck
         
     | 
| 
       71 
     | 
    
         
            -
                  @symmetric_state = nil
         
     | 
| 
       72 
     | 
    
         
            -
                  @cipher_state_handshake = nil
         
     | 
| 
       73 
     | 
    
         
            -
                  @prologue = nil
         
     | 
| 
       74 
     | 
    
         
            -
                  @initiator = nil
         
     | 
| 
       75 
     | 
    
         
            -
                  @dh_fn = nil
         
     | 
| 
       76 
     | 
    
         
            -
                  @hash_fn = nil
         
     | 
| 
       77 
     | 
    
         
            -
                  @keypair_fn = nil
         
     | 
| 
       78 
     | 
    
         
            -
                end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                def validate_psk!
         
     | 
| 
       81 
     | 
    
         
            -
                  # Invalid psk length! Has to be 32 bytes long
         
     | 
| 
       82 
     | 
    
         
            -
                  raise Noise::Exceptions::NoisePSKError if @psks.any? { |psk| psk.bytesize != 32 }
         
     | 
| 
       83 
     | 
    
         
            -
                  # Bad number of PSKs provided to this protocol! {} are required,
         
     | 
| 
       84 
     | 
    
         
            -
                  # given {}'.format(self.pattern.psk_count, len(self.psks)))
         
     | 
| 
       85 
     | 
    
         
            -
                  raise Noise::Exceptions::NoisePSKError if @pattern.psk_count != @psks.count
         
     | 
| 
       86 
     | 
    
         
            -
                end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                def valid_keypairs?
         
     | 
| 
       89 
     | 
    
         
            -
                  @pattern.required_keypairs(@initiator).any? { |keypair| !@keypairs[keypair] }
         
     | 
| 
       90 
     | 
    
         
            -
                end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                def validate
         
     | 
| 
       93 
     | 
    
         
            -
                  validate_psk! if psk_handshake?
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                  # You need to set role with NoiseConnection.set_as_initiator
         
     | 
| 
       96 
     | 
    
         
            -
                  # or NoiseConnection.set_as_responder
         
     | 
| 
       97 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseValidationError if @initiator.nil?
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                  # 'Keypair {} has to be set for chosen handshake pattern'.format(keypair)
         
     | 
| 
       100 
     | 
    
         
            -
                  raise Noise::Exceptions::NoiseValidationError if valid_keypairs?
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                  if @keypairs[:e] || @keypairs[:re]
         
     | 
| 
       103 
     | 
    
         
            -
                    # warnings
         
     | 
| 
       104 
     | 
    
         
            -
                    # One of ephemeral keypairs is already set.
         
     | 
| 
       105 
     | 
    
         
            -
                    # This is OK for testing, but should NEVER happen in production!
         
     | 
| 
       106 
     | 
    
         
            -
                  end
         
     | 
| 
       107 
     | 
    
         
            -
                  true
         
     | 
| 
       108 
     | 
    
         
            -
                end
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                def initialise_handshake_state
         
     | 
| 
       111 
     | 
    
         
            -
                  @handshake_state = Noise::State::HandshakeState.new(
         
     | 
| 
       112 
     | 
    
         
            -
                    self,
         
     | 
| 
       113 
     | 
    
         
            -
                    @initiator,
         
     | 
| 
       114 
     | 
    
         
            -
                    @prologue,
         
     | 
| 
       115 
     | 
    
         
            -
                    @keypairs
         
     | 
| 
       116 
     | 
    
         
            -
                  )
         
     | 
| 
       117 
     | 
    
         
            -
                  @symmetric_state = @handshake_state.symmetric_state
         
     | 
| 
       118 
     | 
    
         
            -
                end
         
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
51 
     | 
    
         
             
                def psk_handshake?
         
     | 
| 
       121 
52 
     | 
    
         
             
                  @is_psk_handshake
         
     | 
| 
       122 
53 
     | 
    
         
             
                end
         
     | 
| 
         @@ -17,11 +17,13 @@ module Noise 
     | 
|
| 
       17 
17 
     | 
    
         
             
                    @cipher = cipher
         
     | 
| 
       18 
18 
     | 
    
         
             
                  end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
                  # @param [String] 32 bytes key
         
     | 
| 
       20 
21 
     | 
    
         
             
                  def initialize_key(key)
         
     | 
| 
       21 
22 
     | 
    
         
             
                    @k = key
         
     | 
| 
       22 
23 
     | 
    
         
             
                    @n = 0
         
     | 
| 
       23 
24 
     | 
    
         
             
                  end
         
     | 
| 
       24 
25 
     | 
    
         | 
| 
      
 26 
     | 
    
         
            +
                  # @return [Boolean] true if k is non-empty, false otherwise.
         
     | 
| 
       25 
27 
     | 
    
         
             
                  def key?
         
     | 
| 
       26 
28 
     | 
    
         
             
                    !@k.nil?
         
     | 
| 
       27 
29 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -30,6 +32,7 @@ module Noise 
     | 
|
| 
       30 
32 
     | 
    
         
             
                    @n = nonce
         
     | 
| 
       31 
33 
     | 
    
         
             
                  end
         
     | 
| 
       32 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
                  #  @return [String] ENCRYPT(k, n++, ad, plaintext) if k is non-empty, otherwise returns plaintext.
         
     | 
| 
       33 
36 
     | 
    
         
             
                  def encrypt_with_ad(ad, plaintext)
         
     | 
| 
       34 
37 
     | 
    
         
             
                    return plaintext unless key?
         
     | 
| 
       35 
38 
     | 
    
         
             
                    raise Noise::Exceptions::MaxNonceError if @n == MAX_NONCE
         
     | 
| 
         @@ -38,6 +41,7 @@ module Noise 
     | 
|
| 
       38 
41 
     | 
    
         
             
                    ciphertext
         
     | 
| 
       39 
42 
     | 
    
         
             
                  end
         
     | 
| 
       40 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
                  # @return DECRYPT(k, n++, ad, ciphertext) if k is non-empty, otherwise returns ciphertext.
         
     | 
| 
       41 
45 
     | 
    
         
             
                  def decrypt_with_ad(ad, ciphertext)
         
     | 
| 
       42 
46 
     | 
    
         
             
                    return ciphertext unless key?
         
     | 
| 
       43 
47 
     | 
    
         
             
                    raise Noise::Exceptions::MaxNonceError if @n == MAX_NONCE
         
     | 
| 
         @@ -10,15 +10,20 @@ module Noise 
     | 
|
| 
       10 
10 
     | 
    
         
             
                # rs: The remote party's static public key
         
     | 
| 
       11 
11 
     | 
    
         
             
                # re: The remote party's ephemeral public key
         
     | 
| 
       12 
12 
     | 
    
         
             
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                # A HandshakeState also has variables to track its role, and the remaining portion of the handshake pattern:
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # initiator: A boolean indicating the initiator or responder role.
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                # message_patterns: A sequence of message patterns.
         
     | 
| 
      
 18 
     | 
    
         
            +
                #     Each message pattern is a sequence of tokens from the set ("e", "s", "ee", "es", "se", "ss").
         
     | 
| 
       13 
19 
     | 
    
         
             
                class HandshakeState
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
20 
     | 
    
         
             
                  attr_reader :message_patterns, :symmetric_state
         
     | 
| 
       16 
21 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                  def initialize(protocol, initiator, prologue, keypairs)
         
     | 
| 
       18 
     | 
    
         
            -
                     
     | 
| 
      
 22 
     | 
    
         
            +
                  def initialize(connection, protocol, initiator, prologue, keypairs)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @connection = connection
         
     | 
| 
       19 
24 
     | 
    
         
             
                    @protocol = protocol
         
     | 
| 
       20 
25 
     | 
    
         
             
                    @symmetric_state = SymmetricState.new
         
     | 
| 
       21 
     | 
    
         
            -
                    @symmetric_state.initialize_symmetric(@protocol)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @symmetric_state.initialize_symmetric(@protocol, connection)
         
     | 
| 
       22 
27 
     | 
    
         
             
                    @symmetric_state.mix_hash(prologue)
         
     | 
| 
       23 
28 
     | 
    
         
             
                    @initiator = initiator
         
     | 
| 
       24 
29 
     | 
    
         
             
                    @s = keypairs[:s]
         
     | 
| 
         @@ -29,7 +34,7 @@ module Noise 
     | 
|
| 
       29 
34 
     | 
    
         
             
                    # TODO : Calls MixHash() once for each public key listed in the pre-messages from  handshake_pattern, with the
         
     | 
| 
       30 
35 
     | 
    
         
             
                    # specified public key as input (see Section 7 for an explanation of pre-messages). If both initiator and
         
     | 
| 
       31 
36 
     | 
    
         
             
                    # responder have pre-messages, the initiator's public keys are hashed first.
         
     | 
| 
       32 
     | 
    
         
            -
                    get_local_keypair = ->(token) { instance_variable_get('@' + token) }
         
     | 
| 
      
 37 
     | 
    
         
            +
                    get_local_keypair = ->(token) { instance_variable_get('@' + token).public_key }
         
     | 
| 
       33 
38 
     | 
    
         
             
                    get_remote_keypair = ->(token) { instance_variable_get('@r' + token) }
         
     | 
| 
       34 
39 
     | 
    
         | 
| 
       35 
40 
     | 
    
         
             
                    if initiator
         
     | 
| 
         @@ -42,17 +47,18 @@ module Noise 
     | 
|
| 
       42 
47 
     | 
    
         | 
| 
       43 
48 
     | 
    
         
             
                    @protocol.pattern.initiator_pre_messages&.map do |message|
         
     | 
| 
       44 
49 
     | 
    
         
             
                      keypair = initiator_keypair_getter.call(message)
         
     | 
| 
       45 
     | 
    
         
            -
                      @symmetric_state.mix_hash(keypair 
     | 
| 
      
 50 
     | 
    
         
            +
                      @symmetric_state.mix_hash(keypair)
         
     | 
| 
       46 
51 
     | 
    
         
             
                    end
         
     | 
| 
       47 
52 
     | 
    
         | 
| 
       48 
53 
     | 
    
         
             
                    @protocol.pattern.responder_pre_messages&.map do |message|
         
     | 
| 
       49 
54 
     | 
    
         
             
                      keypair = responder_keypair_getter.call(message)
         
     | 
| 
       50 
     | 
    
         
            -
                      @symmetric_state.mix_hash(keypair 
     | 
| 
      
 55 
     | 
    
         
            +
                      @symmetric_state.mix_hash(keypair)
         
     | 
| 
       51 
56 
     | 
    
         
             
                    end
         
     | 
| 
       52 
57 
     | 
    
         
             
                    # Sets message_patterns to the message patterns from handshake_pattern
         
     | 
| 
       53 
58 
     | 
    
         
             
                    @message_patterns = @protocol.pattern.tokens.dup
         
     | 
| 
       54 
59 
     | 
    
         
             
                  end
         
     | 
| 
       55 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                  # Takes a payload byte sequence which may be zero-length, and a message_buffer to write the output into
         
     | 
| 
       56 
62 
     | 
    
         
             
                  def write_message(payload, message_buffer)
         
     | 
| 
       57 
63 
     | 
    
         
             
                    pattern = @message_patterns.shift
         
     | 
| 
       58 
64 
     | 
    
         
             
                    dh_fn = @protocol.dh_fn
         
     | 
| 
         @@ -60,37 +66,32 @@ module Noise 
     | 
|
| 
       60 
66 
     | 
    
         
             
                    pattern.each do |token|
         
     | 
| 
       61 
67 
     | 
    
         
             
                      case token
         
     | 
| 
       62 
68 
     | 
    
         
             
                      when 'e'
         
     | 
| 
       63 
     | 
    
         
            -
                        @e = dh_fn.generate_keypair if @e. 
     | 
| 
       64 
     | 
    
         
            -
                        message_buffer << @e 
     | 
| 
       65 
     | 
    
         
            -
                        @symmetric_state.mix_hash(@e 
     | 
| 
       66 
     | 
    
         
            -
                        @symmetric_state.mix_key(@e 
     | 
| 
       67 
     | 
    
         
            -
                        next
         
     | 
| 
      
 69 
     | 
    
         
            +
                        @e = dh_fn.generate_keypair if @e.nil?
         
     | 
| 
      
 70 
     | 
    
         
            +
                        message_buffer << @e.public_key
         
     | 
| 
      
 71 
     | 
    
         
            +
                        @symmetric_state.mix_hash(@e.public_key)
         
     | 
| 
      
 72 
     | 
    
         
            +
                        @symmetric_state.mix_key(@e.public_key) if @protocol.psk_handshake?
         
     | 
| 
       68 
73 
     | 
    
         
             
                      when 's'
         
     | 
| 
       69 
     | 
    
         
            -
                        message_buffer << @symmetric_state.encrypt_and_hash(@s 
     | 
| 
       70 
     | 
    
         
            -
                        next
         
     | 
| 
      
 74 
     | 
    
         
            +
                        message_buffer << @symmetric_state.encrypt_and_hash(@s.public_key)
         
     | 
| 
       71 
75 
     | 
    
         
             
                      when 'ee'
         
     | 
| 
       72 
     | 
    
         
            -
                        @symmetric_state.mix_key(dh_fn.dh(@e 
     | 
| 
       73 
     | 
    
         
            -
                        next
         
     | 
| 
      
 76 
     | 
    
         
            +
                        @symmetric_state.mix_key(dh_fn.dh(@e.private_key, @re))
         
     | 
| 
       74 
77 
     | 
    
         
             
                      when 'es'
         
     | 
| 
       75 
     | 
    
         
            -
                        private_key, public_key = @initiator ? [@e 
     | 
| 
      
 78 
     | 
    
         
            +
                        private_key, public_key = @initiator ? [@e.private_key, @rs] : [@s.private_key, @re]
         
     | 
| 
       76 
79 
     | 
    
         
             
                        @symmetric_state.mix_key(dh_fn.dh(private_key, public_key))
         
     | 
| 
       77 
     | 
    
         
            -
                        next
         
     | 
| 
       78 
80 
     | 
    
         
             
                      when 'se'
         
     | 
| 
       79 
     | 
    
         
            -
                        private_key, public_key = @initiator ? [@s 
     | 
| 
      
 81 
     | 
    
         
            +
                        private_key, public_key = @initiator ? [@s.private_key, @re] : [@e.private_key, @rs]
         
     | 
| 
       80 
82 
     | 
    
         
             
                        @symmetric_state.mix_key(dh_fn.dh(private_key, public_key))
         
     | 
| 
       81 
     | 
    
         
            -
                        next
         
     | 
| 
       82 
83 
     | 
    
         
             
                      when 'ss'
         
     | 
| 
       83 
     | 
    
         
            -
                        @symmetric_state.mix_key(dh_fn.dh(@s 
     | 
| 
       84 
     | 
    
         
            -
                        next
         
     | 
| 
      
 84 
     | 
    
         
            +
                        @symmetric_state.mix_key(dh_fn.dh(@s.private_key, @rs))
         
     | 
| 
       85 
85 
     | 
    
         
             
                      when 'psk'
         
     | 
| 
       86 
     | 
    
         
            -
                        @symmetric_state.mix_key_and_hash(@ 
     | 
| 
       87 
     | 
    
         
            -
                        next
         
     | 
| 
      
 86 
     | 
    
         
            +
                        @symmetric_state.mix_key_and_hash(@connection.psks.shift)
         
     | 
| 
       88 
87 
     | 
    
         
             
                      end
         
     | 
| 
       89 
88 
     | 
    
         
             
                    end
         
     | 
| 
       90 
89 
     | 
    
         
             
                    message_buffer << @symmetric_state.encrypt_and_hash(payload)
         
     | 
| 
       91 
90 
     | 
    
         
             
                    @symmetric_state.split if @message_patterns.empty?
         
     | 
| 
       92 
91 
     | 
    
         
             
                  end
         
     | 
| 
       93 
92 
     | 
    
         | 
| 
      
 93 
     | 
    
         
            +
                  # Takes a byte sequence containing a Noise handshake message,
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # and a payload_buffer to write the message's plaintext payload into
         
     | 
| 
       94 
95 
     | 
    
         
             
                  def read_message(message, payload_buffer)
         
     | 
| 
       95 
96 
     | 
    
         
             
                    pattern = @message_patterns.shift
         
     | 
| 
       96 
97 
     | 
    
         
             
                    dh_fn = @protocol.dh_fn
         
     | 
| 
         @@ -98,44 +99,32 @@ module Noise 
     | 
|
| 
       98 
99 
     | 
    
         
             
                    pattern.each do |token|
         
     | 
| 
       99 
100 
     | 
    
         
             
                      case token
         
     | 
| 
       100 
101 
     | 
    
         
             
                      when 'e'
         
     | 
| 
       101 
     | 
    
         
            -
                        @re =  
     | 
| 
      
 102 
     | 
    
         
            +
                        @re = message[0...len] if @re.nil?
         
     | 
| 
       102 
103 
     | 
    
         
             
                        message = message[len..-1]
         
     | 
| 
       103 
     | 
    
         
            -
                        @symmetric_state.mix_hash(@re 
     | 
| 
       104 
     | 
    
         
            -
                        @symmetric_state.mix_key(@re 
     | 
| 
       105 
     | 
    
         
            -
                        next
         
     | 
| 
      
 104 
     | 
    
         
            +
                        @symmetric_state.mix_hash(@re)
         
     | 
| 
      
 105 
     | 
    
         
            +
                        @symmetric_state.mix_key(@re) if @protocol.psk_handshake?
         
     | 
| 
       106 
106 
     | 
    
         
             
                      when 's'
         
     | 
| 
       107 
     | 
    
         
            -
                        offset = @ 
     | 
| 
      
 107 
     | 
    
         
            +
                        offset = @connection.cipher_state_handshake.key? ? 16 : 0
         
     | 
| 
       108 
108 
     | 
    
         
             
                        temp = message[0...len + offset]
         
     | 
| 
       109 
109 
     | 
    
         
             
                        message = message[(len + offset)..-1]
         
     | 
| 
       110 
     | 
    
         
            -
                        @rs = @ 
     | 
| 
       111 
     | 
    
         
            -
                        next
         
     | 
| 
      
 110 
     | 
    
         
            +
                        @rs = @symmetric_state.decrypt_and_hash(temp)
         
     | 
| 
       112 
111 
     | 
    
         
             
                      when 'ee'
         
     | 
| 
       113 
     | 
    
         
            -
                        @symmetric_state.mix_key(dh_fn.dh(@e 
     | 
| 
       114 
     | 
    
         
            -
                        next
         
     | 
| 
      
 112 
     | 
    
         
            +
                        @symmetric_state.mix_key(dh_fn.dh(@e.private_key, @re))
         
     | 
| 
       115 
113 
     | 
    
         
             
                      when 'es'
         
     | 
| 
       116 
     | 
    
         
            -
                        private_key, public_key = @initiator ? [@e 
     | 
| 
      
 114 
     | 
    
         
            +
                        private_key, public_key = @initiator ? [@e.private_key, @rs] : [@s.private_key, @re]
         
     | 
| 
       117 
115 
     | 
    
         
             
                        @symmetric_state.mix_key(dh_fn.dh(private_key, public_key))
         
     | 
| 
       118 
     | 
    
         
            -
                        next
         
     | 
| 
       119 
116 
     | 
    
         
             
                      when 'se'
         
     | 
| 
       120 
     | 
    
         
            -
                        private_key, public_key = @initiator ? [@s 
     | 
| 
      
 117 
     | 
    
         
            +
                        private_key, public_key = @initiator ? [@s.private_key, @re] : [@e.private_key, @rs]
         
     | 
| 
       121 
118 
     | 
    
         
             
                        @symmetric_state.mix_key(dh_fn.dh(private_key, public_key))
         
     | 
| 
       122 
     | 
    
         
            -
                        next
         
     | 
| 
       123 
119 
     | 
    
         
             
                      when 'ss'
         
     | 
| 
       124 
     | 
    
         
            -
                        @symmetric_state.mix_key(dh_fn.dh(@s 
     | 
| 
       125 
     | 
    
         
            -
                        next
         
     | 
| 
      
 120 
     | 
    
         
            +
                        @symmetric_state.mix_key(dh_fn.dh(@s.private_key, @rs))
         
     | 
| 
       126 
121 
     | 
    
         
             
                      when 'psk'
         
     | 
| 
       127 
     | 
    
         
            -
                        @symmetric_state.mix_key_and_hash(@ 
     | 
| 
       128 
     | 
    
         
            -
                        next
         
     | 
| 
      
 122 
     | 
    
         
            +
                        @symmetric_state.mix_key_and_hash(@connection.psks.shift)
         
     | 
| 
       129 
123 
     | 
    
         
             
                      end
         
     | 
| 
       130 
124 
     | 
    
         
             
                    end
         
     | 
| 
       131 
125 
     | 
    
         
             
                    payload_buffer << @symmetric_state.decrypt_and_hash(message)
         
     | 
| 
       132 
126 
     | 
    
         
             
                    @symmetric_state.split if @message_patterns.empty?
         
     | 
| 
       133 
127 
     | 
    
         
             
                  end
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                  # no need for ephemeral keys after handshake has completed.
         
     | 
| 
       136 
     | 
    
         
            -
                  def keypairs
         
     | 
| 
       137 
     | 
    
         
            -
                    { s: @s, rs: @rs }
         
     | 
| 
       138 
     | 
    
         
            -
                  end
         
     | 
| 
       139 
128 
     | 
    
         
             
                end
         
     | 
| 
       140 
129 
     | 
    
         
             
              end
         
     | 
| 
       141 
130 
     | 
    
         
             
            end
         
     | 
| 
         @@ -11,21 +11,13 @@ module Noise 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  attr_reader :h, :ck
         
     | 
| 
       12 
12 
     | 
    
         
             
                  attr_reader :cipher_state
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                  def  
     | 
| 
       15 
     | 
    
         
            -
                    if protocol.name.length <= protocol.hash_fn.hashlen
         
     | 
| 
       16 
     | 
    
         
            -
                      protocol.name.ljust(protocol.hash_fn.hashlen, "\x00")
         
     | 
| 
       17 
     | 
    
         
            -
                    else
         
     | 
| 
       18 
     | 
    
         
            -
                      protocol.hash_fn.hash(protocol.name)
         
     | 
| 
       19 
     | 
    
         
            -
                    end
         
     | 
| 
       20 
     | 
    
         
            -
                  end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  def initialize_symmetric(protocol)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def initialize_symmetric(protocol, connection)
         
     | 
| 
       23 
15 
     | 
    
         
             
                    @protocol = protocol
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @connection = connection
         
     | 
| 
       24 
17 
     | 
    
         
             
                    @ck = @h = initialize_h(protocol)
         
     | 
| 
       25 
18 
     | 
    
         | 
| 
       26 
19 
     | 
    
         
             
                    @cipher_state = CipherState.new(cipher: @protocol.cipher_fn)
         
     | 
| 
       27 
20 
     | 
    
         
             
                    @cipher_state.initialize_key(nil)
         
     | 
| 
       28 
     | 
    
         
            -
                    @protocol.cipher_state_handshake = @cipher_state
         
     | 
| 
       29 
21 
     | 
    
         
             
                  end
         
     | 
| 
       30 
22 
     | 
    
         | 
| 
       31 
23 
     | 
    
         
             
                  def mix_key(input_key_meterial)
         
     | 
| 
         @@ -34,11 +26,12 @@ module Noise 
     | 
|
| 
       34 
26 
     | 
    
         
             
                    @cipher_state.initialize_key(temp_k)
         
     | 
| 
       35 
27 
     | 
    
         
             
                  end
         
     | 
| 
       36 
28 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                  #  
     | 
| 
      
 29 
     | 
    
         
            +
                  # @param [String] data binary string to be hashed
         
     | 
| 
       38 
30 
     | 
    
         
             
                  def mix_hash(data)
         
     | 
| 
       39 
31 
     | 
    
         
             
                    @h = @protocol.hash_fn.hash(@h + data)
         
     | 
| 
       40 
32 
     | 
    
         
             
                  end
         
     | 
| 
       41 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
                  # This function is used for handling pre-shared symmetric keys.
         
     | 
| 
       42 
35 
     | 
    
         
             
                  def mix_key_and_hash(input_key_meterial)
         
     | 
| 
       43 
36 
     | 
    
         
             
                    @ck, temp_h, temp_k = @protocol.hkdf_fn.call(@ck, input_key_meterial, 3)
         
     | 
| 
       44 
37 
     | 
    
         
             
                    mix_hash(temp_h)
         
     | 
| 
         @@ -46,42 +39,58 @@ module Noise 
     | 
|
| 
       46 
39 
     | 
    
         
             
                    @cipher_state.initialize_key(temp_k)
         
     | 
| 
       47 
40 
     | 
    
         
             
                  end
         
     | 
| 
       48 
41 
     | 
    
         | 
| 
      
 42 
     | 
    
         
            +
                  # Returns h. This function should only be called at the end of a handshake,
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # i.e. after the Split() function has been called.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # This function is used for channel binding
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @returns [String] h
         
     | 
| 
       49 
46 
     | 
    
         
             
                  def handshake_hash
         
     | 
| 
       50 
47 
     | 
    
         
             
                    @h
         
     | 
| 
       51 
48 
     | 
    
         
             
                  end
         
     | 
| 
       52 
49 
     | 
    
         | 
| 
      
 50 
     | 
    
         
            +
                  # Note that if k is empty, the  EncryptWithAd() call will set ciphertext equal to plaintext.
         
     | 
| 
       53 
51 
     | 
    
         
             
                  def encrypt_and_hash(plaintext)
         
     | 
| 
       54 
52 
     | 
    
         
             
                    ciphertext = @cipher_state.encrypt_with_ad(@h, plaintext)
         
     | 
| 
       55 
53 
     | 
    
         
             
                    mix_hash(ciphertext)
         
     | 
| 
       56 
54 
     | 
    
         
             
                    ciphertext
         
     | 
| 
       57 
55 
     | 
    
         
             
                  end
         
     | 
| 
       58 
56 
     | 
    
         | 
| 
      
 57 
     | 
    
         
            +
                  # Note that if k is empty, the  DecryptWithAd() call will set plaintext equal to ciphertext.
         
     | 
| 
       59 
58 
     | 
    
         
             
                  def decrypt_and_hash(ciphertext)
         
     | 
| 
       60 
59 
     | 
    
         
             
                    plaintext = @cipher_state.decrypt_with_ad(@h, ciphertext)
         
     | 
| 
       61 
60 
     | 
    
         
             
                    mix_hash(ciphertext)
         
     | 
| 
       62 
61 
     | 
    
         
             
                    plaintext
         
     | 
| 
       63 
62 
     | 
    
         
             
                  end
         
     | 
| 
       64 
63 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                   
     | 
| 
       66 
     | 
    
         
            -
                    k = truncate(k)
         
     | 
| 
       67 
     | 
    
         
            -
                    c = CipherState.new(cipher: @protocol.cipher_fn)
         
     | 
| 
       68 
     | 
    
         
            -
                    c.initialize_key(k)
         
     | 
| 
       69 
     | 
    
         
            -
                    c
         
     | 
| 
       70 
     | 
    
         
            -
                  end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
                  # @return [CipherState, CipherState] a pair of CipherState objects for encrypting transport messages.
         
     | 
| 
       72 
65 
     | 
    
         
             
                  def split
         
     | 
| 
       73 
66 
     | 
    
         
             
                    temp_k1, temp_k2 = @protocol.hkdf_fn.call(@ck, '', 2)
         
     | 
| 
       74 
67 
     | 
    
         
             
                    c1 = create_cipher_state(temp_k1)
         
     | 
| 
       75 
68 
     | 
    
         
             
                    c2 = create_cipher_state(temp_k2)
         
     | 
| 
       76 
     | 
    
         
            -
                    @ 
     | 
| 
       77 
     | 
    
         
            -
                    @protocol.cipher_state_decrypt = @protocol.initiator ? c2 : c1
         
     | 
| 
       78 
     | 
    
         
            -
                    @protocol.handshake_done
         
     | 
| 
      
 69 
     | 
    
         
            +
                    @connection.handshake_done(c1, c2)
         
     | 
| 
       79 
70 
     | 
    
         
             
                    [c1, c2]
         
     | 
| 
       80 
71 
     | 
    
         
             
                  end
         
     | 
| 
       81 
72 
     | 
    
         | 
| 
      
 73 
     | 
    
         
            +
                  private
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def initialize_h(protocol)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    if protocol.name.length <= protocol.hash_fn.hashlen
         
     | 
| 
      
 77 
     | 
    
         
            +
                      protocol.name.ljust(protocol.hash_fn.hashlen, "\x00")
         
     | 
| 
      
 78 
     | 
    
         
            +
                    else
         
     | 
| 
      
 79 
     | 
    
         
            +
                      protocol.hash_fn.hash(protocol.name)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  # truncates temp_k to 32 bytes if HASHLEN is 64
         
     | 
| 
       82 
84 
     | 
    
         
             
                  def truncate(k)
         
     | 
| 
       83 
85 
     | 
    
         
             
                    @protocol.hash_fn.hashlen == 64 ? k[0, 32] : k
         
     | 
| 
       84 
86 
     | 
    
         
             
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def create_cipher_state(k)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    k = truncate(k)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    c = CipherState.new(cipher: @protocol.cipher_fn)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    c.initialize_key(k)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    c
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
       85 
94 
     | 
    
         
             
                end
         
     | 
| 
       86 
95 
     | 
    
         
             
              end
         
     | 
| 
       87 
96 
     | 
    
         
             
            end
         
     | 
    
        data/lib/noise/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: noise-ruby
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.7. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.7.3
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Hajime Yamaguchi
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2019-04- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-04-28 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bundler
         
     | 
| 
         @@ -128,6 +128,9 @@ files: 
     | 
|
| 
       128 
128 
     | 
    
         
             
            - bin/setup
         
     | 
| 
       129 
129 
     | 
    
         
             
            - lib/noise.rb
         
     | 
| 
       130 
130 
     | 
    
         
             
            - lib/noise/connection.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            - lib/noise/connection/base.rb
         
     | 
| 
      
 132 
     | 
    
         
            +
            - lib/noise/connection/initiator.rb
         
     | 
| 
      
 133 
     | 
    
         
            +
            - lib/noise/connection/responder.rb
         
     | 
| 
       131 
134 
     | 
    
         
             
            - lib/noise/exceptions.rb
         
     | 
| 
       132 
135 
     | 
    
         
             
            - lib/noise/exceptions/decrypt_error.rb
         
     | 
| 
       133 
136 
     | 
    
         
             
            - lib/noise/exceptions/encrypt_error.rb
         
     | 
| 
         @@ -151,6 +154,7 @@ files: 
     | 
|
| 
       151 
154 
     | 
    
         
             
            - lib/noise/functions/hash/blake2s.rb
         
     | 
| 
       152 
155 
     | 
    
         
             
            - lib/noise/functions/hash/sha256.rb
         
     | 
| 
       153 
156 
     | 
    
         
             
            - lib/noise/functions/hash/sha512.rb
         
     | 
| 
      
 157 
     | 
    
         
            +
            - lib/noise/key.rb
         
     | 
| 
       154 
158 
     | 
    
         
             
            - lib/noise/key_pair.rb
         
     | 
| 
       155 
159 
     | 
    
         
             
            - lib/noise/pattern.rb
         
     | 
| 
       156 
160 
     | 
    
         
             
            - lib/noise/protocol.rb
         
     |