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
|