noise-ruby 0.11.0 → 0.12.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/Dockerfile +3 -3
- data/README.md +25 -18
- data/lib/noise/connection/base.rb +88 -7
- data/lib/noise/exceptions/invalid_nonce_error.rb +9 -0
- data/lib/noise/exceptions/message_too_long_error.rb +11 -0
- data/lib/noise/exceptions.rb +2 -0
- data/lib/noise/functions/dh/ed25519.rb +12 -0
- data/lib/noise/functions/dh/ed448.rb +29 -12
- data/lib/noise/functions/dh/secp256k1.rb +14 -1
- data/lib/noise/state/cipher_state.rb +13 -0
- data/lib/noise/version.rb +1 -1
- data/lib/noise.rb +1 -0
- data/noise.gemspec +4 -1
- metadata +10 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a3f4c1b701c2de6240cb5fc0fb2410e1790c390142b256e6b822af4fa327cef
|
|
4
|
+
data.tar.gz: a57735c978c1227262bc122e869aa6866e76a943654981fb57411d70cab34f80
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 915a8da57226d70b24a5a7289325eba851d1e7e40c7d7ef0d0081411008f388a78eec00a760fe92f05ef82ccd707bc776bc8d4d385a6e14d1c3184714b7437b3
|
|
7
|
+
data.tar.gz: dd660c060e00d5c1d0c0e89c434743d6e91749ba09d16a8217e0031c641a2788636ba0fbf64bcfcc031ed84c75e290e3526d95af40fc6518a0211b1e292f7d77
|
data/Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# check=skip=FromPlatformFlagConstDisallowed
|
|
2
|
-
# The test suite loads the x86_64 libsecp256k1
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# The test suite loads the x86_64 libsecp256k1 bundled in spec/lib, and spec/spec_helper.rb
|
|
3
|
+
# points at it unconditionally, so this image has to be linux/amd64 even on an arm64 host.
|
|
4
|
+
# It mirrors the CI runner (ubuntu x86_64).
|
|
5
5
|
FROM --platform=linux/amd64 ruby:3.3
|
|
6
6
|
|
|
7
7
|
# libsodium: dlopen'd by rbnacl, which lib/noise.rb requires unconditionally.
|
data/README.md
CHANGED
|
@@ -47,24 +47,6 @@ Or install it yourself as:
|
|
|
47
47
|
|
|
48
48
|
$ gem install noise-ruby
|
|
49
49
|
|
|
50
|
-
If you use Ed448 as DH function, you must install [libgoldilocks](https://github.com/otrv4/libgoldilocks).
|
|
51
|
-
|
|
52
|
-
After installing, define an environment variable as follows:
|
|
53
|
-
|
|
54
|
-
* on macOS
|
|
55
|
-
|
|
56
|
-
$ export LIBGOLDILOCKS=/usr/local/lib/libgoldilocks.dylib
|
|
57
|
-
|
|
58
|
-
* on Linux(Ubuntu)
|
|
59
|
-
|
|
60
|
-
$ export LIBGOLDILOCKS=/usr/local/lib/libgoldilocks.so
|
|
61
|
-
|
|
62
|
-
and, add this line to your Gemfile:
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
gem 'ed448'
|
|
66
|
-
```
|
|
67
|
-
|
|
68
50
|
If you use Secp256k1, you must install [libsecp256k1](https://github.com/bitcoin-core/secp256k1).
|
|
69
51
|
|
|
70
52
|
$ git clone https://github.com/bitcoin-core/secp256k1
|
|
@@ -138,6 +120,31 @@ cipher = initiator.encrypt("Hello, World!") # => "\xDA\xC7\xD7as\v\xFA\xCC,\xB3\
|
|
|
138
120
|
plain = responder.decrypt(cipher) # => "Hello, World!"
|
|
139
121
|
```
|
|
140
122
|
|
|
123
|
+
#### Out-of-order transport messages
|
|
124
|
+
|
|
125
|
+
Each party counts the transport messages of each direction with a nonce. If the transport layer can
|
|
126
|
+
deliver messages out of order or lose them, it has to carry the nonce of each message, and the
|
|
127
|
+
receiver sets the nonce before decrypting. Restore the previous value if the message fails to
|
|
128
|
+
authenticate, so that the following messages are still decryptable.
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
initiator.encryption_nonce # => 0
|
|
132
|
+
responder.decryption_nonce = 2 # decrypt the message numbered 2 next
|
|
133
|
+
plain = responder.decrypt(cipher)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Rekey
|
|
137
|
+
|
|
138
|
+
Rekeying replaces the key of one direction with `REKEY(k)`, so that a key compromised later cannot
|
|
139
|
+
decrypt the messages that came before it. The nonce keeps counting. Both parties must rekey the
|
|
140
|
+
matching direction at the same point of the message stream; when that happens is up to the
|
|
141
|
+
application protocol.
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
initiator.rekey_encryption
|
|
145
|
+
responder.rekey_decryption
|
|
146
|
+
```
|
|
147
|
+
|
|
141
148
|
## Development
|
|
142
149
|
|
|
143
150
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
module Noise
|
|
4
4
|
module Connection
|
|
5
5
|
class Base
|
|
6
|
-
# The Noise spec caps a handshake or transport message at 65535 bytes.
|
|
6
|
+
# The Noise spec caps a handshake or transport message at 65535 bytes. A transport message is
|
|
7
|
+
# the ciphertext, so the plaintext a caller may hand to encrypt is shorter by the
|
|
8
|
+
# authentication tag that ENCRYPT() appends.
|
|
7
9
|
MAX_MESSAGE_LENGTH = 65_535
|
|
10
|
+
MAX_PLAINTEXT_LENGTH = MAX_MESSAGE_LENGTH - Noise::State::CipherState::TAG_LENGTH
|
|
8
11
|
|
|
9
12
|
attr_reader :protocol, :handshake_started, :handshake_finished, :handshake_hash, :handshake_state,
|
|
10
13
|
:cipher_state_encrypt, :cipher_state_decrypt, :cipher_state_handshake, :s, :rs
|
|
@@ -86,21 +89,82 @@ module Noise
|
|
|
86
89
|
end
|
|
87
90
|
|
|
88
91
|
def encrypt(data)
|
|
89
|
-
|
|
92
|
+
cipher_state = transport_cipher_state(:encrypt)
|
|
93
|
+
if data.bytesize > MAX_PLAINTEXT_LENGTH
|
|
94
|
+
raise Noise::Exceptions::MessageTooLongError,
|
|
95
|
+
"Plaintext is #{data.bytesize} bytes, which exceeds the maximum of #{MAX_PLAINTEXT_LENGTH}."
|
|
96
|
+
end
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
cipher_state.encrypt_with_ad('', data)
|
|
92
99
|
end
|
|
93
100
|
|
|
94
101
|
def decrypt(data)
|
|
95
|
-
|
|
102
|
+
cipher_state = transport_cipher_state(:decrypt)
|
|
103
|
+
# Rejected before the cipher state is used, so an over-long message leaves n untouched
|
|
104
|
+
# and the connection usable, exactly as a failed decryption does.
|
|
105
|
+
if data.bytesize > MAX_MESSAGE_LENGTH
|
|
106
|
+
raise Noise::Exceptions::MessageTooLongError,
|
|
107
|
+
"Message is #{data.bytesize} bytes, which exceeds the maximum of #{MAX_MESSAGE_LENGTH}."
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
cipher_state.decrypt_with_ad('', data)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [Integer] the nonce the next #encrypt call uses.
|
|
114
|
+
def encryption_nonce
|
|
115
|
+
transport_cipher_state(:encrypt).n
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @return [Integer] the nonce the next #decrypt call uses.
|
|
119
|
+
def decryption_nonce
|
|
120
|
+
transport_cipher_state(:decrypt).n
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Sets the nonce of the next #encrypt call. Needed when the transport layer numbers the
|
|
124
|
+
# messages itself instead of relying on the sender and the receiver counting in step.
|
|
125
|
+
#
|
|
126
|
+
# @param [Integer] nonce a value between 0 and CipherState::MAX_NONCE.
|
|
127
|
+
def encryption_nonce=(nonce)
|
|
128
|
+
transport_cipher_state(:encrypt).nonce = nonce
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Sets the nonce of the next #decrypt call. This is how the Noise spec handles transport
|
|
132
|
+
# messages that arrive out of order: the receiver sets n to the nonce of the message it is
|
|
133
|
+
# about to decrypt, and restores the previous value if the message fails to authenticate.
|
|
134
|
+
#
|
|
135
|
+
# @param [Integer] nonce a value between 0 and CipherState::MAX_NONCE.
|
|
136
|
+
def decryption_nonce=(nonce)
|
|
137
|
+
transport_cipher_state(:decrypt).nonce = nonce
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Replaces the key used by #encrypt with REKEY(k), so that the old key cannot decrypt the
|
|
141
|
+
# messages that follow. Both parties must rekey the matching direction at the same point of
|
|
142
|
+
# the message stream, which is up to the application protocol to agree on.
|
|
143
|
+
#
|
|
144
|
+
# @return [void]
|
|
145
|
+
def rekey_encryption
|
|
146
|
+
transport_cipher_state(:encrypt).rekey
|
|
147
|
+
nil
|
|
148
|
+
end
|
|
96
149
|
|
|
97
|
-
|
|
150
|
+
# Replaces the key used by #decrypt with REKEY(k). See #rekey_encryption.
|
|
151
|
+
#
|
|
152
|
+
# @return [void]
|
|
153
|
+
def rekey_decryption
|
|
154
|
+
transport_cipher_state(:decrypt).rekey
|
|
155
|
+
nil
|
|
98
156
|
end
|
|
99
157
|
|
|
100
158
|
def validate_psk!
|
|
159
|
+
raise Noise::Exceptions::NoisePSKError, 'psks are not set.' if @psks.nil?
|
|
101
160
|
# Invalid psk length! Has to be 32 bytes long
|
|
102
|
-
raise Noise::Exceptions::NoisePSKError
|
|
103
|
-
|
|
161
|
+
raise Noise::Exceptions::NoisePSKError, 'psks have to be 32 bytes long.' if
|
|
162
|
+
@psks.any? { |psk| psk.bytesize != 32 }
|
|
163
|
+
|
|
164
|
+
return if @protocol.pattern.psk_count == @psks.count
|
|
165
|
+
|
|
166
|
+
raise Noise::Exceptions::NoisePSKError,
|
|
167
|
+
"This protocol needs #{@protocol.pattern.psk_count} psks, got #{@psks.count}."
|
|
104
168
|
end
|
|
105
169
|
|
|
106
170
|
def missing_keypairs?
|
|
@@ -124,6 +188,23 @@ module Noise
|
|
|
124
188
|
@symmetric_state = nil
|
|
125
189
|
@cipher_state_handshake = nil
|
|
126
190
|
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
# Returns the transport CipherState of the given direction.
|
|
195
|
+
#
|
|
196
|
+
# One-way patterns leave the direction the caller cannot use as nil, so the absence of a
|
|
197
|
+
# cipher state is reported the same way as a handshake that has not finished yet.
|
|
198
|
+
#
|
|
199
|
+
# @param [Symbol] direction :encrypt or :decrypt.
|
|
200
|
+
def transport_cipher_state(direction)
|
|
201
|
+
raise Noise::Exceptions::NoiseHandshakeError unless @handshake_finished
|
|
202
|
+
|
|
203
|
+
cipher_state = direction == :encrypt ? @cipher_state_encrypt : @cipher_state_decrypt
|
|
204
|
+
raise Noise::Exceptions::NoiseHandshakeError, "This party cannot #{direction} messages." unless cipher_state
|
|
205
|
+
|
|
206
|
+
cipher_state
|
|
207
|
+
end
|
|
127
208
|
end
|
|
128
209
|
end
|
|
129
210
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Noise
|
|
4
|
+
module Exceptions
|
|
5
|
+
# Raised when a transport message would exceed, or does exceed, the 65535 byte limit the Noise
|
|
6
|
+
# specification places on every message. Kept apart from DecryptError so that a caller can tell a
|
|
7
|
+
# badly framed message from a failed authentication, which has very different security meaning.
|
|
8
|
+
class MessageTooLongError < StandardError
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
data/lib/noise/exceptions.rb
CHANGED
|
@@ -4,8 +4,10 @@ module Noise
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
autoload :DecryptError, 'noise/exceptions/decrypt_error'
|
|
6
6
|
autoload :EncryptError, 'noise/exceptions/encrypt_error'
|
|
7
|
+
autoload :InvalidNonceError, 'noise/exceptions/invalid_nonce_error'
|
|
7
8
|
autoload :InvalidPublicKeyError, 'noise/exceptions/invalid_public_key_error'
|
|
8
9
|
autoload :MaxNonceError, 'noise/exceptions/max_nonce_error'
|
|
10
|
+
autoload :MessageTooLongError, 'noise/exceptions/message_too_long_error'
|
|
9
11
|
autoload :MissingDependencyError, 'noise/exceptions/missing_dependency_error'
|
|
10
12
|
autoload :ProtocolNameError, 'noise/exceptions/protocol_name_error'
|
|
11
13
|
autoload :NoiseHandshakeError, 'noise/exceptions/noise_handshake_error'
|
|
@@ -12,8 +12,20 @@ module Noise
|
|
|
12
12
|
Noise::Key.new(ECDSA::Format::IntegerOctetString.encode(private_key, 32), public_key.to_bytes)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# Computes the X25519 shared secret for the given remote public key.
|
|
16
|
+
#
|
|
17
|
+
# RbNaCl reports a public key it cannot use in two different ways: a wrong length
|
|
18
|
+
# raises RbNaCl::LengthError, and an all-zero or low-order point raises
|
|
19
|
+
# RbNaCl::CryptoError. Both are translated to InvalidPublicKeyError so that a
|
|
20
|
+
# caller handling a peer-supplied key rescues the same class for every DH function.
|
|
21
|
+
# The length is checked before the call so that RbNaCl::LengthError raised for a
|
|
22
|
+
# malformed private key keeps propagating as itself.
|
|
15
23
|
def dh(private_key, public_key)
|
|
24
|
+
raise Noise::Exceptions::InvalidPublicKeyError, public_key unless public_key.bytesize == DHLEN
|
|
25
|
+
|
|
16
26
|
RbNaCl::GroupElement.new(public_key).mult(private_key).to_bytes
|
|
27
|
+
rescue RbNaCl::CryptoError
|
|
28
|
+
raise Noise::Exceptions::InvalidPublicKeyError, public_key
|
|
17
29
|
end
|
|
18
30
|
|
|
19
31
|
def dhlen
|
|
@@ -1,26 +1,43 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
Noise.require_optional('ed448') { Ed448.init }
|
|
4
|
-
|
|
5
3
|
module Noise
|
|
6
4
|
module Functions
|
|
7
5
|
module DH
|
|
6
|
+
# The 448 DH function of the Noise specification, which is X448 as defined by RFC 7748 and
|
|
7
|
+
# not the Ed448 signature scheme the class name suggests. The name is kept because it is what
|
|
8
|
+
# Protocol::DH maps '448' to and what callers reference.
|
|
9
|
+
#
|
|
10
|
+
# OpenSSL implements X448 and exposes it through the raw key interface, so this function needs
|
|
11
|
+
# no gem and no system library beyond the OpenSSL that AesGcm and the HMAC helpers already use.
|
|
8
12
|
class ED448
|
|
9
|
-
# Ed448::X448::X448_PRIVATE_BYTES, spelled out so this file loads without the gem.
|
|
10
13
|
DHLEN = 56
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
# The name OpenSSL knows the curve by. Ed448 is a different algorithm, and asking for it
|
|
16
|
+
# here would produce a signing key rather than one that can derive a shared secret.
|
|
17
|
+
ALGORITHM = 'X448'
|
|
15
18
|
|
|
16
19
|
def generate_keypair
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Noise::Key.new(private_key, public_key)
|
|
20
|
+
pkey = OpenSSL::PKey.generate_key(ALGORITHM)
|
|
21
|
+
Noise::Key.new(pkey.raw_private_key, pkey.raw_public_key)
|
|
20
22
|
end
|
|
21
23
|
|
|
24
|
+
# Computes the X448 shared secret for the given remote public key.
|
|
25
|
+
#
|
|
26
|
+
# OpenSSL reports a public key it cannot use as OpenSSL::PKey::PKeyError, both when the key
|
|
27
|
+
# is not DHLEN bytes and when the derivation would produce the all-zero output that RFC 7748
|
|
28
|
+
# requires be rejected. Both are translated to InvalidPublicKeyError so that a caller
|
|
29
|
+
# handling a peer-supplied key rescues the same class for every DH function. The local key
|
|
30
|
+
# is built outside the rescue so that a malformed private key keeps propagating as
|
|
31
|
+
# PKeyError instead of being reported as the peer's fault.
|
|
22
32
|
def dh(private_key, public_key)
|
|
23
|
-
|
|
33
|
+
raise Noise::Exceptions::InvalidPublicKeyError, public_key unless public_key.bytesize == DHLEN
|
|
34
|
+
|
|
35
|
+
local = OpenSSL::PKey.new_raw_private_key(ALGORITHM, private_key)
|
|
36
|
+
begin
|
|
37
|
+
local.derive(OpenSSL::PKey.new_raw_public_key(ALGORITHM, public_key))
|
|
38
|
+
rescue OpenSSL::PKey::PKeyError
|
|
39
|
+
raise Noise::Exceptions::InvalidPublicKeyError, public_key
|
|
40
|
+
end
|
|
24
41
|
end
|
|
25
42
|
|
|
26
43
|
def dhlen
|
|
@@ -28,8 +45,8 @@ module Noise
|
|
|
28
45
|
end
|
|
29
46
|
|
|
30
47
|
def self.from_private(private_key)
|
|
31
|
-
|
|
32
|
-
Noise::Key.new(private_key,
|
|
48
|
+
pkey = OpenSSL::PKey.new_raw_private_key(ALGORITHM, private_key)
|
|
49
|
+
Noise::Key.new(private_key, pkey.raw_public_key)
|
|
33
50
|
end
|
|
34
51
|
end
|
|
35
52
|
end
|
|
@@ -6,6 +6,10 @@ module Noise
|
|
|
6
6
|
module Functions
|
|
7
7
|
module DH
|
|
8
8
|
class Secp256k1
|
|
9
|
+
# Length of a compressed secp256k1 point. libsecp256k1 also accepts the 65-byte
|
|
10
|
+
# uncompressed form, but Noise exchanges only the compressed one.
|
|
11
|
+
DHLEN = 33
|
|
12
|
+
|
|
9
13
|
def initialize
|
|
10
14
|
Noise.optional_dependency!('secp256k1')
|
|
11
15
|
end
|
|
@@ -20,7 +24,16 @@ module Noise
|
|
|
20
24
|
)
|
|
21
25
|
end
|
|
22
26
|
|
|
27
|
+
# Computes the ECDH shared secret for the given remote public key.
|
|
28
|
+
#
|
|
29
|
+
# A point that is not on the curve makes libsecp256k1 raise Secp256k1::AssertError,
|
|
30
|
+
# while a public key of any other length raises ArgumentError before the point is
|
|
31
|
+
# even parsed. Both are translated to InvalidPublicKeyError, matching the other DH
|
|
32
|
+
# functions. The length is checked here rather than left to the gem so that
|
|
33
|
+
# ArgumentError raised for a malformed private key keeps propagating as itself.
|
|
23
34
|
def dh(private_key, public_key)
|
|
35
|
+
raise Noise::Exceptions::InvalidPublicKeyError, public_key unless public_key.bytesize == DHLEN
|
|
36
|
+
|
|
24
37
|
key = ::Secp256k1::PublicKey.new(pubkey: public_key, raw: true)
|
|
25
38
|
key.ecdh(private_key)
|
|
26
39
|
rescue ::Secp256k1::AssertError
|
|
@@ -28,7 +41,7 @@ module Noise
|
|
|
28
41
|
end
|
|
29
42
|
|
|
30
43
|
def dhlen
|
|
31
|
-
|
|
44
|
+
DHLEN
|
|
32
45
|
end
|
|
33
46
|
|
|
34
47
|
def self.from_private(private_key)
|
|
@@ -29,7 +29,17 @@ module Noise
|
|
|
29
29
|
!@k.nil?
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Sets n, the nonce the next encrypt_with_ad or decrypt_with_ad call uses. This is SetNonce()
|
|
33
|
+
# of the Noise spec, needed to decrypt transport messages that arrive out of order.
|
|
34
|
+
#
|
|
35
|
+
# The value is checked here because the ciphers pack n into 8 bytes: a value outside the
|
|
36
|
+
# unsigned 64-bit range silently produces a wrong nonce instead of an error.
|
|
37
|
+
#
|
|
38
|
+
# @param [Integer] nonce a value between 0 and MAX_NONCE.
|
|
39
|
+
# @raise [Noise::Exceptions::InvalidNonceError] if nonce is out of that range.
|
|
32
40
|
def nonce=(nonce)
|
|
41
|
+
raise Noise::Exceptions::InvalidNonceError unless nonce.is_a?(Integer) && nonce.between?(0, MAX_NONCE)
|
|
42
|
+
|
|
33
43
|
@n = nonce
|
|
34
44
|
end
|
|
35
45
|
|
|
@@ -56,6 +66,9 @@ module Noise
|
|
|
56
66
|
plaintext
|
|
57
67
|
end
|
|
58
68
|
|
|
69
|
+
# Replaces k with REKEY(k). n is left as it is, as the Noise spec requires.
|
|
70
|
+
#
|
|
71
|
+
# @return [String] the new 32 bytes key.
|
|
59
72
|
def rekey
|
|
60
73
|
@k = @cipher.rekey(@k)
|
|
61
74
|
end
|
data/lib/noise/version.rb
CHANGED
data/lib/noise.rb
CHANGED
data/noise.gemspec
CHANGED
|
@@ -35,10 +35,13 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
# each also needs a system library that cannot be installed as a gem, so none of them is a runtime
|
|
36
36
|
# dependency. Add the one you need to your own Gemfile; see the README for the system libraries.
|
|
37
37
|
spec.add_development_dependency 'blake3'
|
|
38
|
-
spec.add_development_dependency 'ed448'
|
|
39
38
|
spec.add_development_dependency 'secp256k1-ruby'
|
|
40
39
|
|
|
41
40
|
spec.add_runtime_dependency 'ecdsa'
|
|
41
|
+
# The 448 DH function needs the raw key API (OpenSSL::PKey.new_raw_private_key and friends),
|
|
42
|
+
# which arrived in openssl 3.0. Ruby 3.0 still ships 2.2 as its default gem, so the version has
|
|
43
|
+
# to be requested explicitly rather than left to whatever the interpreter bundles.
|
|
44
|
+
spec.add_runtime_dependency 'openssl', '>= 3.0'
|
|
42
45
|
spec.add_runtime_dependency 'rbnacl'
|
|
43
46
|
spec.add_runtime_dependency 'ruby-hmac'
|
|
44
47
|
end
|
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.12.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: 2026-
|
|
11
|
+
date: 2026-08-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -123,7 +123,7 @@ dependencies:
|
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name:
|
|
126
|
+
name: secp256k1-ruby
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
128
128
|
requirements:
|
|
129
129
|
- - ">="
|
|
@@ -137,13 +137,13 @@ dependencies:
|
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
|
-
name:
|
|
140
|
+
name: ecdsa
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
142
142
|
requirements:
|
|
143
143
|
- - ">="
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
145
|
version: '0'
|
|
146
|
-
type: :
|
|
146
|
+
type: :runtime
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
@@ -151,19 +151,19 @@ dependencies:
|
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
152
|
version: '0'
|
|
153
153
|
- !ruby/object:Gem::Dependency
|
|
154
|
-
name:
|
|
154
|
+
name: openssl
|
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
|
156
156
|
requirements:
|
|
157
157
|
- - ">="
|
|
158
158
|
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
159
|
+
version: '3.0'
|
|
160
160
|
type: :runtime
|
|
161
161
|
prerelease: false
|
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
163
163
|
requirements:
|
|
164
164
|
- - ">="
|
|
165
165
|
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
166
|
+
version: '3.0'
|
|
167
167
|
- !ruby/object:Gem::Dependency
|
|
168
168
|
name: rbnacl
|
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -220,8 +220,10 @@ files:
|
|
|
220
220
|
- lib/noise/exceptions.rb
|
|
221
221
|
- lib/noise/exceptions/decrypt_error.rb
|
|
222
222
|
- lib/noise/exceptions/encrypt_error.rb
|
|
223
|
+
- lib/noise/exceptions/invalid_nonce_error.rb
|
|
223
224
|
- lib/noise/exceptions/invalid_public_key_error.rb
|
|
224
225
|
- lib/noise/exceptions/max_nonce_error.rb
|
|
226
|
+
- lib/noise/exceptions/message_too_long_error.rb
|
|
225
227
|
- lib/noise/exceptions/missing_dependency_error.rb
|
|
226
228
|
- lib/noise/exceptions/noise_handshake_error.rb
|
|
227
229
|
- lib/noise/exceptions/noise_psk_error.rb
|