noise-ruby 0.3.0 → 0.5.0
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/.rubocop.yml +3 -1
- data/Gemfile +3 -1
- data/README.md +11 -1
- data/Rakefile +3 -1
- data/lib/noise/connection.rb +2 -8
- data/lib/noise/functions/cipher/cha_cha_poly.rb +1 -1
- data/lib/noise/functions/dh/secp256k1.rb +3 -6
- data/lib/noise/key_pair.rb +10 -0
- data/lib/noise/pattern.rb +4 -10
- data/lib/noise/protocol.rb +26 -26
- data/lib/noise/state/handshake_state.rb +7 -7
- data/lib/noise/state/symmetric_state.rb +20 -14
- data/lib/noise/version.rb +1 -1
- data/lib/noise.rb +2 -0
- data/noise.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61342d193c1bb42324605f5be2643542fac0bc2b
|
4
|
+
data.tar.gz: 44dec9620e075573cf4af4b44367506c45e71b8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e613f8379f2309a540b1e5a9a9b2f884220fcb39387720a1b5ee978fbb0e698f013ba09435e6a2834c45c5534d413b8d8fd76159bc90a748b219417d49b3fa7
|
7
|
+
data.tar.gz: 72b2c24e768d729b67d6a54d26efb71b0acbed829a66725113ce0a953092a6e6543801bf0f936c3ac80dfa11dd3870d02b74ba556d11eff6c7efe4bfb8cca579
|
data/.rubocop.yml
CHANGED
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
|
-
|
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
data/lib/noise/connection.rb
CHANGED
@@ -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 =
|
26
|
-
@read_message_proc =
|
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,15 +15,12 @@ module Noise
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def dh(private_key, public_key)
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
+
33
|
27
24
|
end
|
28
25
|
|
29
26
|
def self.from_private(private_key)
|
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
|
-
|
39
|
-
|
40
|
-
|
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
|
data/lib/noise/protocol.rb
CHANGED
@@ -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:
|
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 =
|
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
|
-
|
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
|
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,
|
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]
|
25
|
-
@e = [e]
|
26
|
-
@rs = [rs]
|
27
|
-
@re = [re]
|
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.
|
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.
|
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
|
-
|
65
|
-
|
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(
|
77
|
-
@protocol.hash_fn.hashlen == 64 ?
|
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
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.
|
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-
|
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
|