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 +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
|