noise-ruby 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b311addeddc717377b96beaecbe50300759ea5d6
4
- data.tar.gz: 2979832b1b009280a5998de859bead7cae613b00
3
+ metadata.gz: 61342d193c1bb42324605f5be2643542fac0bc2b
4
+ data.tar.gz: 44dec9620e075573cf4af4b44367506c45e71b8b
5
5
  SHA512:
6
- metadata.gz: 176002bdc3b0763255c0c2679485e38aa9d9795477dd7d789f40cebaa2154ae877fcec6593ab0409f095447cfd49f565aac8216053742bc3dce3572fc9a67253
7
- data.tar.gz: ac57838f8ab1e3a0f8910dae97cb8d28a8b9a83bec9b6e433316c062c1f2c09465c149ace734db23d0da6360bb5c1f12545f3ad858f72a87cca045ae89554ad9
6
+ metadata.gz: 4e613f8379f2309a540b1e5a9a9b2f884220fcb39387720a1b5ee978fbb0e698f013ba09435e6a2834c45c5534d413b8d8fd76159bc90a748b219417d49b3fa7
7
+ data.tar.gz: 72b2c24e768d729b67d6a54d26efb71b0acbed829a66725113ce0a953092a6e6543801bf0f936c3ac80dfa11dd3870d02b74ba556d11eff6c7efe4bfb8cca579
data/.rubocop.yml CHANGED
@@ -4,6 +4,9 @@ Metrics/BlockLength:
4
4
  Metrics/LineLength:
5
5
  Max: 120
6
6
 
7
+ Metrics/MethodLength:
8
+ Max: 30
9
+
7
10
  Style/Documentation:
8
11
  Enabled: false
9
12
 
@@ -18,4 +21,3 @@ Style/WordArray:
18
21
 
19
22
  AllCops:
20
23
  TargetRubyVersion: 2.4.1
21
-
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in noise.gemspec
6
8
  gemspec
data/README.md CHANGED
@@ -6,7 +6,8 @@ A Ruby implementation of the Noise Protocol framework(http://noiseprotocol.org/)
6
6
 
7
7
  Secp256k1 cipher function is supported.
8
8
  This is required for Lightning Network, layer-2 protocol for bitcoin.
9
- see
9
+
10
+ see https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md
10
11
 
11
12
  ## Future Works
12
13
 
@@ -19,6 +20,15 @@ The followings are not supported yet.
19
20
 
20
21
  ## Installation
21
22
 
23
+ This library requires [libsecp256k1](https://github.com/bitcoin-core/secp256k1).
24
+
25
+ $ git clone https://github.com/bitcoin-core/secp256k1
26
+ $ cd secp256k1
27
+ $ ./autogen.sh
28
+ $ ./configure --enable-experimental --enable-module-ecdh --enable-module-recovery --enable-benchmark=false
29
+ $ make
30
+ $ sudo make install
31
+
22
32
  Add this line to your application's Gemfile:
23
33
 
24
34
  ```
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Noise
4
- module KeyPair
5
- STATIC = 's'
6
- EPHEMERAL = 'e'
7
- REMOTE_STATIC = 'rs'
8
- REMOTE_EPHEMERAL = 're'
9
- end
10
4
  class Connection
11
5
  module Status
12
6
  STATIC = 1
@@ -22,8 +16,8 @@ module Noise
22
16
  @handshake_started = false
23
17
  @handshake_finished = false
24
18
  @fn = nil
25
- @write_message_proc = lambda {|payload| write_message(payload)}
26
- @read_message_proc = lambda {|payload| read_message(payload)}
19
+ @write_message_proc = ->(payload) { write_message(payload) }
20
+ @read_message_proc = ->(payload) { read_message(payload) }
27
21
  end
28
22
 
29
23
  def psks=(psks)
@@ -15,7 +15,7 @@ module Noise
15
15
  end
16
16
 
17
17
  def nonce_to_bytes(n)
18
- "\00" * 4 + sprintf('%16x', n).htb.reverse
18
+ "\00" * 4 + format('%16x', n).htb.reverse
19
19
  end
20
20
  end
21
21
  end
@@ -15,15 +15,12 @@ module Noise
15
15
  end
16
16
 
17
17
  def dh(private_key, public_key)
18
- group = ECDSA::Group::Secp256k1
19
- point = ECDSA::Format::PointOctetString.decode(public_key, group)
20
- scalar = ECDSA::Format::IntegerOctetString.decode(private_key)
21
- point = point.multiply_by_scalar(scalar)
22
- ECDSA::Format::PointOctetString.encode(point, compression: true)
18
+ key = ::Secp256k1::PublicKey.new(pubkey: public_key, raw: true)
19
+ key.ecdh(private_key)
23
20
  end
24
21
 
25
22
  def dhlen
26
- 64
23
+ 33
27
24
  end
28
25
 
29
26
  def self.from_private(private_key)
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noise
4
+ module KeyPair
5
+ STATIC = 's'
6
+ EPHEMERAL = 'e'
7
+ REMOTE_STATIC = 'rs'
8
+ REMOTE_EPHEMERAL = 're'
9
+ end
10
+ end
data/lib/noise/pattern.rb CHANGED
@@ -12,7 +12,7 @@ module Noise
12
12
  end
13
13
 
14
14
  class Pattern
15
- attr_reader :one_way, :tokens, :modifiers
15
+ attr_reader :one_way, :tokens, :modifiers, :psk_count
16
16
 
17
17
  def self.create(name)
18
18
  pattern_set = name.scan(/([A-Z]+)([^A-Z]*)/)&.first
@@ -35,15 +35,9 @@ module Noise
35
35
  def apply_pattern_modifiers
36
36
  @modifiers.each do |modifier|
37
37
  if modifier.start_with?('psk')
38
- begin
39
- index = modifier.gsub(/psk/, '').to_i
40
- rescue
41
- raise Noise::Exceptions::PSKValueError
42
- end
43
- # if index * 2 > @tokens.size
44
- # raise PSKValueError
45
- # end
46
- if index == 0
38
+ index = modifier.gsub(/psk/, '').to_i
39
+ raise Noise::Exceptions::PSKValueError if index / 2 > @tokens.size
40
+ if index.zero?
47
41
  @tokens[0].insert(0, Token::PSK)
48
42
  else
49
43
  @tokens[index - 1] << Token::PSK
@@ -17,7 +17,8 @@ module Noise
17
17
 
18
18
  DH = {
19
19
  '25519': Noise::Functions::DH::ED25519,
20
- '448': Noise::Functions::DH::ED448
20
+ '448': Noise::Functions::DH::ED448,
21
+ 'secp256k1': Noise::Functions::DH::Secp256k1
21
22
  }.stringify_keys.freeze
22
23
 
23
24
  HASH = {
@@ -36,16 +37,20 @@ module Noise
36
37
  def initialize(name, pattern_name, cipher_name, hash_name, dh_name)
37
38
  @name = name
38
39
  @pattern = Noise::Pattern.create(pattern_name)
39
- @keypairs = { s: nil, e: nil, rs: nil, re: nil }
40
- @cipher_fn = CIPHER[cipher_name]&.new
41
- @hash_fn = HASH[hash_name]&.new
42
- @dh_fn = DH[dh_name]&.new
40
+ @keypairs = { s: [], e: [], rs: [], re: [] }
43
41
  @hkdf_fn = Noise::Functions::Hash.create_hkdf_fn(hash_name)
44
- @psks = nil
42
+ @psks = []
45
43
  @is_psk_handshake = @pattern.modifiers.any? { |m| m.start_with?('psk') }
46
44
 
47
45
  @pattern.apply_pattern_modifiers
48
46
 
47
+ initialize_fn!(cipher_name, hash_name, dh_name)
48
+ end
49
+
50
+ def initialize_fn!(cipher_name, hash_name, dh_name)
51
+ @cipher_fn = CIPHER[cipher_name]&.new
52
+ @hash_fn = HASH[hash_name]&.new
53
+ @dh_fn = DH[dh_name]&.new
49
54
  raise Noise::Exceptions::ProtocolNameError unless @cipher_fn && @hash_fn && @dh_fn
50
55
  end
51
56
 
@@ -66,38 +71,36 @@ module Noise
66
71
  @dh_fn = nil
67
72
  @hash_fn = nil
68
73
  @keypair_fn = nil
74
+ end
75
+
76
+ def validate_psk!
77
+ # Invalid psk length! Has to be 32 bytes long
78
+ raise Noise::Exceptions::NoisePSKError if @psks.any? { |psk| psk.bytesize != 32 }
79
+ # Bad number of PSKs provided to this protocol! {} are required,
80
+ # given {}'.format(self.pattern.psk_count, len(self.psks)))
81
+ raise Noise::Exceptions::NoisePSKError if @pattern.psk_count != @psks.count
82
+ end
69
83
 
84
+ def valid_keypairs?
85
+ @pattern.required_keypairs(@initiator).any? { |keypair| !@keypairs[keypair] }
70
86
  end
71
87
 
72
88
  def validate
73
- if psk_handshake?
74
- if @psks.any? {|psk| psk.bytesize != 32}
75
- raise NoisePSKError # Invalid psk length! Has to be 32 bytes long
76
- end
77
- if @pattern.psk_count != @psks.count
78
- # Bad number of PSKs provided to this protocol! {} are required,
79
- # given {}'.format(self.pattern.psk_count, len(self.psks)))
80
- raise NoisePSKError
81
- end
82
- end
89
+ validate_psk! if psk_handshake?
83
90
 
84
91
  # You need to set role with NoiseConnection.set_as_initiator
85
92
  # or NoiseConnection.set_as_responder
86
93
  raise Noise::Exceptions::NoiseValidationError if @initiator.nil?
87
94
 
88
95
  # 'Keypair {} has to be set for chosen handshake pattern'.format(keypair)
89
- # require 'pp'
90
- # pp @pattern
91
- # pp @initiator
92
- # pp @pattern.required_keypairs(@initiator)
93
- # pp @keypairs
94
- raise Noise::Exceptions::NoiseValidationError if @pattern.required_keypairs(@initiator).any? { |keypair| !@keypairs[keypair] }
96
+ raise Noise::Exceptions::NoiseValidationError if valid_keypairs?
95
97
 
96
98
  if @keypairs[:e] || @keypairs[:re]
97
99
  # warnings
98
100
  # One of ephemeral keypairs is already set.
99
101
  # This is OK for testing, but should NEVER happen in production!
100
102
  end
103
+ true
101
104
  end
102
105
 
103
106
  def initialise_handshake_state
@@ -105,10 +108,7 @@ module Noise
105
108
  self,
106
109
  @initiator,
107
110
  @prologue,
108
- @keypairs[:s],
109
- @keypairs[:e],
110
- @keypairs[:rs],
111
- @keypairs[:re]
111
+ @keypairs
112
112
  )
113
113
  @symmetric_state = @handshake_state.symmetric_state
114
114
  end
@@ -14,17 +14,17 @@ module Noise
14
14
 
15
15
  attr_reader :message_patterns, :symmetric_state
16
16
 
17
- def initialize(protocol, initiator, prologue, s, e, rs, re)
17
+ def initialize(protocol, initiator, prologue, keypairs)
18
18
  # @protocol = handshake_pattern.to_protocol
19
19
  @protocol = protocol
20
20
  @symmetric_state = SymmetricState.new
21
21
  @symmetric_state.initialize_symmetric(@protocol)
22
22
  @symmetric_state.mix_hash(prologue)
23
23
  @initiator = initiator
24
- @s = [s].flatten
25
- @e = [e].flatten
26
- @rs = [rs].flatten
27
- @re = [re].flatten
24
+ @s = keypairs[:s]
25
+ @e = keypairs[:e]
26
+ @rs = keypairs[:rs]
27
+ @re = keypairs[:re]
28
28
 
29
29
  # TODO : Calls MixHash() once for each public key listed in the pre-messages from handshake_pattern, with the
30
30
  # specified public key as input (see Section 7 for an explanation of pre-messages). If both initiator and
@@ -60,7 +60,7 @@ module Noise
60
60
  pattern.each do |token|
61
61
  case token
62
62
  when 'e'
63
- @e = dh_fn.generate_keypair if @e.compact.empty?
63
+ @e = dh_fn.generate_keypair if @e.empty?
64
64
  message_buffer << @e[1]
65
65
  @symmetric_state.mix_hash(@e[1])
66
66
  @symmetric_state.mix_key(@e[1]) if @protocol.psk_handshake?
@@ -104,7 +104,7 @@ module Noise
104
104
  pattern.each do |token|
105
105
  case token
106
106
  when 'e'
107
- @re = @protocol.dh_fn.class.from_public(message[0...len]) if @re.compact.empty?
107
+ @re = @protocol.dh_fn.class.from_public(message[0...len]) if @re.empty?
108
108
  message = message[len..-1]
109
109
  @symmetric_state.mix_hash(@re[1])
110
110
  @symmetric_state.mix_key(@re[1]) if @protocol.psk_handshake?
@@ -11,14 +11,17 @@ module Noise
11
11
  attr_reader :h, :ck
12
12
  attr_reader :cipher_state
13
13
 
14
+ def initialize_h(protocol)
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
+
14
22
  def initialize_symmetric(protocol)
15
23
  @protocol = protocol
16
- @ck = @h =
17
- if @protocol.name.length <= @protocol.hash_fn.hashlen
18
- @protocol.name.ljust(@protocol.hash_fn.hashlen, "\x00")
19
- else
20
- @protocol.hash_fn.hash(@protocol.name)
21
- end
24
+ @ck = @h = initialize_h(protocol)
22
25
 
23
26
  @cipher_state = CipherState.new(cipher: @protocol.cipher_fn)
24
27
  @cipher_state.initialize_key(nil)
@@ -59,22 +62,25 @@ module Noise
59
62
  plaintext
60
63
  end
61
64
 
65
+ def create_cipher_state(k)
66
+ k = truncate(k)
67
+ c = CipherState.new(cipher: @protocol.cipher_fn)
68
+ c.initialize_key(k)
69
+ c
70
+ end
71
+
62
72
  def split
63
73
  temp_k1, temp_k2 = @protocol.hkdf_fn.call(@ck, '', 2)
64
- temp_k1 = truncate(temp_k1)
65
- temp_k2 = truncate(temp_k2)
66
- c1 = CipherState.new(cipher: @protocol.cipher_fn)
67
- c2 = CipherState.new(cipher: @protocol.cipher_fn)
68
- c1.initialize_key(temp_k1)
69
- c2.initialize_key(temp_k2)
74
+ c1 = create_cipher_state(temp_k1)
75
+ c2 = create_cipher_state(temp_k2)
70
76
  @protocol.cipher_state_encrypt = @protocol.initiator ? c1 : c2
71
77
  @protocol.cipher_state_decrypt = @protocol.initiator ? c2 : c1
72
78
  @protocol.handshake_done
73
79
  [c1, c2]
74
80
  end
75
81
 
76
- def truncate(temp_k)
77
- @protocol.hash_fn.hashlen == 64 ? temp_k[0, 32] : temp_k
82
+ def truncate(k)
83
+ @protocol.hash_fn.hashlen == 64 ? k[0, 32] : k
78
84
  end
79
85
  end
80
86
  end
data/lib/noise/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Noise
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/noise.rb CHANGED
@@ -5,6 +5,7 @@ require 'noise/version'
5
5
  require 'ecdsa'
6
6
  require 'rbnacl'
7
7
  require 'ruby_hmac'
8
+ require 'secp256k1'
8
9
  require 'securerandom'
9
10
 
10
11
  require 'noise/utils/hash'
@@ -12,6 +13,7 @@ require 'noise/utils/string'
12
13
 
13
14
  module Noise
14
15
  autoload :Connection, 'noise/connection'
16
+ autoload :KeyPair, 'noise/key_pair'
15
17
  autoload :Protocol, 'noise/protocol'
16
18
  autoload :Pattern, 'noise/pattern'
17
19
  autoload :Exceptions, 'noise/exceptions'
data/noise.gemspec CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'rspec', '~> 3.0'
27
27
 
28
28
  spec.add_runtime_dependency 'aead'
29
+ spec.add_runtime_dependency 'bitcoin-secp256k1'
29
30
  spec.add_runtime_dependency 'ecdsa'
30
31
  spec.add_runtime_dependency 'rbnacl'
31
32
  spec.add_runtime_dependency 'ruby-hmac'
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.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hajime Yamaguchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-08 00:00:00.000000000 Z
11
+ date: 2017-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bitcoin-secp256k1
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: ecdsa
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -148,6 +162,7 @@ files:
148
162
  - lib/noise/functions/hash/blake2s.rb
149
163
  - lib/noise/functions/hash/sha256.rb
150
164
  - lib/noise/functions/hash/sha512.rb
165
+ - lib/noise/key_pair.rb
151
166
  - lib/noise/pattern.rb
152
167
  - lib/noise/protocol.rb
153
168
  - lib/noise/state.rb