noise-ruby 0.7.1 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|