rbnacl 1.1.0 → 2.0.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
- checksums.yaml.gz.sig +0 -0
- data/.travis.yml +1 -5
- data/CHANGES.md +27 -0
- data/Gemfile +4 -1
- data/Guardfile +8 -0
- data/README.md +52 -3
- data/lib/rbnacl/auth.rb +22 -19
- data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/private_key.rb +26 -23
- data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key.rb +13 -12
- data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +185 -0
- data/lib/rbnacl/group_elements/curve25519.rb +81 -0
- data/lib/rbnacl/hash/blake2b.rb +64 -0
- data/lib/rbnacl/hash/sha256.rb +15 -0
- data/lib/rbnacl/hash/sha512.rb +15 -0
- data/lib/rbnacl/hash.rb +30 -14
- data/lib/rbnacl/hmac/sha256.rb +19 -17
- data/lib/rbnacl/hmac/sha512256.rb +18 -19
- data/lib/rbnacl/init.rb +10 -0
- data/lib/rbnacl/{keys/key_comparator.rb → key_comparator.rb} +1 -1
- data/lib/rbnacl/{auth/one_time.rb → one_time_auths/poly1305.rb} +21 -19
- data/lib/rbnacl/rake_tasks.rb +7 -6
- data/lib/rbnacl/random.rb +12 -3
- data/lib/rbnacl/random_nonce_box.rb +9 -14
- data/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb +125 -0
- data/lib/rbnacl/self_test.rb +67 -43
- data/lib/rbnacl/serializable.rb +4 -12
- data/lib/rbnacl/signatures/ed25519/signing_key.rb +104 -0
- data/lib/rbnacl/signatures/ed25519/verify_key.rb +78 -0
- data/lib/rbnacl/signatures/ed25519.rb +15 -0
- data/lib/rbnacl/sodium/version.rb +23 -0
- data/lib/rbnacl/sodium.rb +43 -0
- data/lib/rbnacl/test_vectors.rb +34 -1
- data/lib/rbnacl/util.rb +50 -7
- data/lib/rbnacl/version.rb +2 -2
- data/lib/rbnacl.rb +64 -29
- data/rbnacl.gemspec +6 -5
- data/spec/rbnacl/{auth/one_time_spec.rb → authenticators/poly1305_spec.rb} +2 -2
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb +65 -0
- data/spec/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key_spec.rb +10 -13
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +39 -0
- data/spec/rbnacl/{point_spec.rb → group_element_spec.rb} +6 -8
- data/spec/rbnacl/hash/blake2b_spec.rb +30 -0
- data/spec/rbnacl/hash_spec.rb +13 -33
- data/spec/rbnacl/hmac/sha256_spec.rb +2 -2
- data/spec/rbnacl/hmac/sha512256_spec.rb +2 -2
- data/spec/rbnacl/random_nonce_box_spec.rb +21 -26
- data/spec/rbnacl/random_spec.rb +3 -3
- data/spec/rbnacl/secret_box_spec.rb +6 -6
- data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +30 -0
- data/spec/rbnacl/signatures/ed25519/verify_key_spec.rb +39 -0
- data/spec/rbnacl/util_spec.rb +67 -53
- data/spec/shared/authenticator.rb +36 -55
- data/spec/shared/box.rb +10 -10
- data/spec/shared/key_equality.rb +3 -3
- data/spec/shared/serializable.rb +17 -0
- data/spec/spec_helper.rb +15 -16
- data/tasks/rspec.rake +1 -0
- data.tar.gz.sig +2 -3
- metadata +41 -42
- metadata.gz.sig +2 -2
- data/lib/rbnacl/box.rb +0 -171
- data/lib/rbnacl/encoder.rb +0 -44
- data/lib/rbnacl/encoders/base32.rb +0 -33
- data/lib/rbnacl/encoders/base64.rb +0 -30
- data/lib/rbnacl/encoders/hex.rb +0 -30
- data/lib/rbnacl/encoders/raw.rb +0 -12
- data/lib/rbnacl/keys/signing_key.rb +0 -95
- data/lib/rbnacl/keys/verify_key.rb +0 -96
- data/lib/rbnacl/nacl.rb +0 -146
- data/lib/rbnacl/point.rb +0 -70
- data/lib/rbnacl/secret_box.rb +0 -119
- data/spec/rbnacl/box_spec.rb +0 -42
- data/spec/rbnacl/encoder_spec.rb +0 -14
- data/spec/rbnacl/encoders/base32_spec.rb +0 -16
- data/spec/rbnacl/encoders/base64_spec.rb +0 -15
- data/spec/rbnacl/encoders/hex_spec.rb +0 -15
- data/spec/rbnacl/keys/private_key_spec.rb +0 -68
- data/spec/rbnacl/keys/signing_key_spec.rb +0 -39
- data/spec/rbnacl/keys/verify_key_spec.rb +0 -51
data/lib/rbnacl/self_test.rb
CHANGED
|
@@ -1,41 +1,52 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
|
|
1
3
|
start = Time.now if $DEBUG
|
|
2
4
|
|
|
3
|
-
module
|
|
4
|
-
class SelfTestFailure <
|
|
5
|
+
module RbNaCl
|
|
6
|
+
class SelfTestFailure < RbNaCl::CryptoError; end
|
|
5
7
|
|
|
6
8
|
module SelfTest
|
|
7
9
|
module_function
|
|
8
10
|
|
|
11
|
+
def vector(name)
|
|
12
|
+
[TestVectors[name]].pack("H*")
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
def box_test
|
|
10
|
-
alicepk =
|
|
11
|
-
bobsk =
|
|
16
|
+
alicepk = RbNaCl::PublicKey.new(vector(:alice_public))
|
|
17
|
+
bobsk = RbNaCl::PrivateKey.new(vector(:bob_private))
|
|
12
18
|
|
|
13
|
-
box =
|
|
19
|
+
box = RbNaCl::Box.new(alicepk, bobsk)
|
|
14
20
|
box_common_test(box)
|
|
15
21
|
end
|
|
16
22
|
|
|
17
23
|
def secret_box_test
|
|
18
|
-
box = SecretBox.new(
|
|
24
|
+
box = SecretBox.new(vector(:secret_key))
|
|
19
25
|
box_common_test(box)
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def box_common_test(box)
|
|
23
|
-
nonce =
|
|
24
|
-
message =
|
|
25
|
-
ciphertext =
|
|
29
|
+
nonce = vector :box_nonce
|
|
30
|
+
message = vector :box_message
|
|
31
|
+
ciphertext = vector :box_ciphertext
|
|
26
32
|
|
|
27
33
|
unless box.encrypt(nonce, message) == ciphertext
|
|
34
|
+
#:nocov:
|
|
28
35
|
raise SelfTestFailure, "failed to generate correct ciphertext"
|
|
36
|
+
#:nocov:
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
unless box.decrypt(nonce, ciphertext) == message
|
|
40
|
+
#:nocov:
|
|
32
41
|
raise SelfTestFailure, "failed to decrypt ciphertext correctly"
|
|
42
|
+
#:nocov:
|
|
33
43
|
end
|
|
34
44
|
|
|
35
45
|
begin
|
|
36
46
|
passed = false
|
|
37
47
|
corrupt_ct = ciphertext.dup
|
|
38
48
|
corrupt_ct[23] = ' '
|
|
49
|
+
corrupt_ct
|
|
39
50
|
box.decrypt(nonce, corrupt_ct)
|
|
40
51
|
rescue CryptoError
|
|
41
52
|
passed = true
|
|
@@ -45,74 +56,87 @@ module Crypto
|
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
def digital_signature_test
|
|
48
|
-
signing_key = SigningKey.new(
|
|
59
|
+
signing_key = SigningKey.new(vector(:sign_private))
|
|
49
60
|
verify_key = signing_key.verify_key
|
|
50
61
|
|
|
51
|
-
unless verify_key.to_s
|
|
62
|
+
unless verify_key.to_s == vector(:sign_public)
|
|
63
|
+
#:nocov:
|
|
52
64
|
raise SelfTestFailure, "failed to generate verify key correctly"
|
|
65
|
+
#:nocov:
|
|
53
66
|
end
|
|
54
67
|
|
|
55
|
-
message =
|
|
56
|
-
signature = signing_key.sign(message
|
|
68
|
+
message = vector :sign_message
|
|
69
|
+
signature = signing_key.sign(message)
|
|
57
70
|
|
|
58
|
-
unless signature ==
|
|
71
|
+
unless signature == vector(:sign_signature)
|
|
72
|
+
#:nocov:
|
|
59
73
|
raise SelfTestFailure, "failed to generate correct signature"
|
|
74
|
+
#:nocov:
|
|
60
75
|
end
|
|
61
76
|
|
|
62
|
-
unless verify_key.verify(
|
|
77
|
+
unless verify_key.verify(signature, message)
|
|
78
|
+
#:nocov:
|
|
63
79
|
raise SelfTestFailure, "failed to verify a valid signature"
|
|
80
|
+
#:nocov:
|
|
64
81
|
end
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
begin
|
|
84
|
+
passed = false
|
|
85
|
+
bad_signature = signature[0,63] + '0'
|
|
86
|
+
verify_key.verify(bad_signature, message)
|
|
87
|
+
rescue CryptoError
|
|
88
|
+
passed = true
|
|
89
|
+
ensure
|
|
90
|
+
passed or raise SelfTestFailure, "failed to detect corrupt ciphertext"
|
|
70
91
|
end
|
|
71
92
|
end
|
|
72
93
|
|
|
73
94
|
def sha256_test
|
|
74
|
-
message =
|
|
75
|
-
digest =
|
|
95
|
+
message = vector :sha256_message
|
|
96
|
+
digest = vector :sha256_digest
|
|
76
97
|
|
|
77
|
-
unless
|
|
98
|
+
unless RbNaCl::Hash.sha256(message) == digest
|
|
99
|
+
#:nocov:
|
|
78
100
|
raise SelfTestFailure, "failed to generate a correct SHA256 digest"
|
|
101
|
+
#:nocov:
|
|
79
102
|
end
|
|
80
103
|
end
|
|
81
104
|
|
|
82
105
|
def hmac_test(klass, tag)
|
|
83
|
-
authenticator = klass.new(
|
|
106
|
+
authenticator = klass.new(vector(:auth_key))
|
|
84
107
|
|
|
85
|
-
message =
|
|
108
|
+
message = vector :auth_message
|
|
86
109
|
|
|
87
|
-
unless authenticator.auth(message
|
|
110
|
+
unless authenticator.auth(message) == vector(tag)
|
|
111
|
+
#:nocov:
|
|
88
112
|
raise SelfTestFailure, "#{klass} failed to generate correct authentication tag"
|
|
113
|
+
#:nocov:
|
|
89
114
|
end
|
|
90
115
|
|
|
91
|
-
unless authenticator.verify(
|
|
116
|
+
unless authenticator.verify(vector(tag), message)
|
|
117
|
+
#:nocov:
|
|
92
118
|
raise SelfTestFailure, "#{klass} failed to verify correct authentication tag"
|
|
119
|
+
#:nocov:
|
|
93
120
|
end
|
|
94
121
|
|
|
95
|
-
|
|
96
|
-
|
|
122
|
+
begin
|
|
123
|
+
passed = false
|
|
124
|
+
authenticator.verify(vector(tag), message + ' ')
|
|
125
|
+
rescue CryptoError
|
|
126
|
+
passed = true
|
|
127
|
+
ensure
|
|
128
|
+
passed or raise SelfTestFailure, "failed to detect corrupt ciphertext"
|
|
97
129
|
end
|
|
98
130
|
end
|
|
99
|
-
|
|
100
|
-
def hexdecode(string)
|
|
101
|
-
Encoder[:hex].decode(string)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def hexdecode_vector(name)
|
|
105
|
-
hexdecode TestVectors[name]
|
|
106
|
-
end
|
|
107
131
|
end
|
|
108
132
|
end
|
|
109
133
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
RbNaCl::SelfTest.box_test
|
|
135
|
+
RbNaCl::SelfTest.secret_box_test
|
|
136
|
+
RbNaCl::SelfTest.digital_signature_test
|
|
137
|
+
RbNaCl::SelfTest.sha256_test
|
|
138
|
+
RbNaCl::SelfTest.hmac_test RbNaCl::HMAC::SHA256, :auth_hmacsha256
|
|
139
|
+
RbNaCl::SelfTest.hmac_test RbNaCl::HMAC::SHA512256, :auth_hmacsha512256
|
|
140
|
+
RbNaCl::SelfTest.hmac_test RbNaCl::OneTimeAuth, :auth_onetime
|
|
117
141
|
|
|
118
142
|
puts "POST Completed in #{Time.now - start} s" if $DEBUG
|
data/lib/rbnacl/serializable.rb
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
-
module
|
|
2
|
+
module RbNaCl
|
|
3
3
|
# Serialization features shared across all "key-like" classes
|
|
4
4
|
module Serializable
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
# @param encoding [String] string encoding format in which to encode the key
|
|
9
|
-
#
|
|
10
|
-
# @return [String] key encoded in the specified format
|
|
11
|
-
def to_s(encoding = :raw)
|
|
12
|
-
Encoder[encoding].encode(to_bytes)
|
|
13
|
-
end
|
|
14
|
-
alias_method :to_str, :to_s
|
|
5
|
+
def to_s; to_bytes; end
|
|
6
|
+
def to_str; to_bytes; end
|
|
15
7
|
|
|
16
8
|
# Inspect this key
|
|
17
9
|
#
|
|
18
10
|
# @return [String] a string representing this key
|
|
19
11
|
def inspect
|
|
20
|
-
"#<#{self.class}:#{
|
|
12
|
+
"#<#{self.class}:#{Util.bin2hex(to_bytes)[0,8]}>"
|
|
21
13
|
end
|
|
22
14
|
end
|
|
23
15
|
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
module RbNaCl
|
|
3
|
+
module Signatures
|
|
4
|
+
module Ed25519
|
|
5
|
+
# Private key for producing digital signatures using the Ed25519 algorithm.
|
|
6
|
+
# Ed25519 provides a 128-bit security level, that is to say, all known attacks
|
|
7
|
+
# take at least 2^128 operations, providing the same security level as
|
|
8
|
+
# AES-128, NIST P-256, and RSA-3072.
|
|
9
|
+
#
|
|
10
|
+
# Signing keys are produced from a 32-byte (256-bit) random seed value.
|
|
11
|
+
# This value can be passed into the SigningKey constructor as a String
|
|
12
|
+
# whose bytesize is 32.
|
|
13
|
+
#
|
|
14
|
+
# The public VerifyKey can be computed from the private 32-byte seed value
|
|
15
|
+
# as well, eliminating the need to store a "keypair".
|
|
16
|
+
#
|
|
17
|
+
# SigningKey produces 64-byte (512-bit) signatures. The signatures are
|
|
18
|
+
# deterministic: signing the same message will always produce the same
|
|
19
|
+
# signature. This prevents "entropy failure" seen in other signature
|
|
20
|
+
# algorithms like DSA and ECDSA, where poor random number generators can
|
|
21
|
+
# leak enough information to recover the private key.
|
|
22
|
+
class SigningKey
|
|
23
|
+
include KeyComparator
|
|
24
|
+
include Serializable
|
|
25
|
+
|
|
26
|
+
extend Sodium
|
|
27
|
+
|
|
28
|
+
sodium_type :sign
|
|
29
|
+
sodium_primitive :ed25519
|
|
30
|
+
|
|
31
|
+
sodium_function :sign_ed25519,
|
|
32
|
+
:crypto_sign_ed25519,
|
|
33
|
+
[:pointer, :pointer, :pointer, :ulong_long, :pointer]
|
|
34
|
+
|
|
35
|
+
sodium_function :sign_ed25519_seed_keypair,
|
|
36
|
+
:crypto_sign_ed25519_seed_keypair,
|
|
37
|
+
[:pointer, :pointer, :pointer]
|
|
38
|
+
|
|
39
|
+
attr_reader :verify_key
|
|
40
|
+
|
|
41
|
+
# Generate a random SigningKey
|
|
42
|
+
#
|
|
43
|
+
# @return [RbNaCl::SigningKey] Freshly-generated random SigningKey
|
|
44
|
+
def self.generate
|
|
45
|
+
new RbNaCl::Random.random_bytes(Ed25519::SEEDBYTES)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Create a SigningKey from a seed value
|
|
49
|
+
#
|
|
50
|
+
# @param seed [String] Random 32-byte value (i.e. private key)
|
|
51
|
+
#
|
|
52
|
+
# @return [RbNaCl::SigningKey] Key which can sign messages
|
|
53
|
+
def initialize(seed)
|
|
54
|
+
seed = seed.to_s
|
|
55
|
+
|
|
56
|
+
Util.check_length(seed, Ed25519::SEEDBYTES, "seed")
|
|
57
|
+
|
|
58
|
+
pk = Util.zeros(Ed25519::VERIFYKEYBYTES)
|
|
59
|
+
sk = Util.zeros(Ed25519::SIGNINGKEYBYTES)
|
|
60
|
+
|
|
61
|
+
self.class.sign_ed25519_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair")
|
|
62
|
+
|
|
63
|
+
@seed, @signing_key = seed, sk
|
|
64
|
+
@verify_key = VerifyKey.new(pk)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Sign a message using this key
|
|
68
|
+
#
|
|
69
|
+
# @param message [String] Message to be signed by this key
|
|
70
|
+
#
|
|
71
|
+
# @return [String] Signature as bytes
|
|
72
|
+
def sign(message)
|
|
73
|
+
buffer = Util.prepend_zeros(signature_bytes, message)
|
|
74
|
+
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)
|
|
75
|
+
|
|
76
|
+
self.class.sign_ed25519(buffer, buffer_len, message, message.bytesize, @signing_key)
|
|
77
|
+
|
|
78
|
+
buffer[0, signature_bytes]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Return the raw seed value of this key
|
|
82
|
+
#
|
|
83
|
+
# @return [String] seed used to create this key
|
|
84
|
+
def to_bytes; @seed; end
|
|
85
|
+
|
|
86
|
+
# The crypto primitive this SigningKey class uses for signatures
|
|
87
|
+
#
|
|
88
|
+
# @return [Symbol] The primitive
|
|
89
|
+
def primitive; self.class.primitive; end
|
|
90
|
+
|
|
91
|
+
# The size of signatures generated by the SigningKey class
|
|
92
|
+
#
|
|
93
|
+
# @return [Integer] The number of bytes in a signature
|
|
94
|
+
def self.signature_bytes; Ed25519::SIGNATUREBYTES; end
|
|
95
|
+
|
|
96
|
+
# The size of signatures generated by the SigningKey instance
|
|
97
|
+
#
|
|
98
|
+
# @return [Integer] The number of bytes in a signature
|
|
99
|
+
def signature_bytes; Ed25519::SIGNATUREBYTES; end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
module RbNaCl
|
|
3
|
+
module Signatures
|
|
4
|
+
module Ed25519
|
|
5
|
+
# The public key counterpart to an Ed25519 SigningKey for producing digital
|
|
6
|
+
# signatures. Like the name says, VerifyKeys can be used to verify that a
|
|
7
|
+
# given digital signature is authentic.
|
|
8
|
+
#
|
|
9
|
+
# For more information on the Ed25519 digital signature system, please see
|
|
10
|
+
# the SigningKey documentation.
|
|
11
|
+
class VerifyKey
|
|
12
|
+
include KeyComparator
|
|
13
|
+
include Serializable
|
|
14
|
+
|
|
15
|
+
extend Sodium
|
|
16
|
+
|
|
17
|
+
sodium_type :sign
|
|
18
|
+
sodium_primitive :ed25519
|
|
19
|
+
|
|
20
|
+
sodium_function :sign_ed25519_open,
|
|
21
|
+
:crypto_sign_ed25519_open,
|
|
22
|
+
[:pointer, :pointer, :pointer, :ulong_long, :pointer]
|
|
23
|
+
|
|
24
|
+
# Create a new VerifyKey object from a public key.
|
|
25
|
+
#
|
|
26
|
+
# @param key [String] Ed25519 public key
|
|
27
|
+
#
|
|
28
|
+
# @return [RbNaCl::VerifyKey] Key which can verify messages
|
|
29
|
+
def initialize(key)
|
|
30
|
+
@key = key.to_str
|
|
31
|
+
Util.check_length(@key, Ed25519::VERIFYKEYBYTES, "key")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Verify a signature for a given message
|
|
35
|
+
#
|
|
36
|
+
# Raises if the signature is invalid.
|
|
37
|
+
#
|
|
38
|
+
# @param signature [String] Alleged signature to be checked
|
|
39
|
+
# @param message [String] Message to be authenticated
|
|
40
|
+
#
|
|
41
|
+
# @raise [BadSignatureError] if the signature check fails
|
|
42
|
+
# @raise [LengthError] if the signature is of the wrong length
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean] was the signature authentic?
|
|
45
|
+
def verify(signature, message)
|
|
46
|
+
signature = signature.to_str
|
|
47
|
+
Util.check_length(signature, signature_bytes, "signature")
|
|
48
|
+
|
|
49
|
+
sig_and_msg = signature + message
|
|
50
|
+
buffer = Util.zeros(sig_and_msg.bytesize)
|
|
51
|
+
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)
|
|
52
|
+
|
|
53
|
+
self.class.sign_ed25519_open(buffer, buffer_len, sig_and_msg, sig_and_msg.bytesize, @key) || raise(BadSignatureError, "signature was forged/corrupt")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return the raw key in byte format
|
|
57
|
+
#
|
|
58
|
+
# @return [String] raw key as bytes
|
|
59
|
+
def to_bytes; @key; end
|
|
60
|
+
|
|
61
|
+
# The crypto primitive this VerifyKey class uses for signatures
|
|
62
|
+
#
|
|
63
|
+
# @return [Symbol] The primitive
|
|
64
|
+
def primitive; self.class.primitive; end
|
|
65
|
+
|
|
66
|
+
# The size of signatures verified by the VerifyKey class
|
|
67
|
+
#
|
|
68
|
+
# @return [Integer] The number of bytes in a signature
|
|
69
|
+
def self.signature_bytes; Ed25519::SIGNATUREBYTES; end
|
|
70
|
+
|
|
71
|
+
# The size of signatures verified by the VerifyKey instance
|
|
72
|
+
#
|
|
73
|
+
# @return [Integer] The number of bytes in a signature
|
|
74
|
+
def signature_bytes; Ed25519::SIGNATUREBYTES; end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
module RbNaCl
|
|
3
|
+
module Signatures
|
|
4
|
+
module Ed25519
|
|
5
|
+
extend Sodium
|
|
6
|
+
|
|
7
|
+
sodium_type :sign
|
|
8
|
+
sodium_primitive :ed25519
|
|
9
|
+
sodium_constant :SEEDBYTES
|
|
10
|
+
sodium_constant :PUBLICKEYBYTES, :VERIFYKEYBYTES
|
|
11
|
+
sodium_constant :SECRETKEYBYTES, :SIGNINGKEYBYTES
|
|
12
|
+
sodium_constant :BYTES, :SIGNATUREBYTES
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'rbnacl/sodium'
|
|
2
|
+
|
|
3
|
+
module RbNaCl
|
|
4
|
+
module Sodium
|
|
5
|
+
module Version
|
|
6
|
+
MINIMUM_LIBSODIUM_VERSION = "0.4.3"
|
|
7
|
+
|
|
8
|
+
extend Sodium
|
|
9
|
+
attach_function :sodium_version_string, [], :string
|
|
10
|
+
|
|
11
|
+
STRING = sodium_version_string
|
|
12
|
+
MAJOR, MINOR, PATCH = STRING.split(".").map(&:to_i)
|
|
13
|
+
|
|
14
|
+
installed_version = [MAJOR, MINOR, PATCH]
|
|
15
|
+
minimum_version = MINIMUM_LIBSODIUM_VERSION.split(".").map(&:to_i)
|
|
16
|
+
|
|
17
|
+
case installed_version <=> minimum_version
|
|
18
|
+
when -1
|
|
19
|
+
raise "Sorry, you need to install libsodium #{MINIMUM_LIBSODIUM_VERSION}+. You have #{Version::STRING} installed"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
require 'ffi'
|
|
3
|
+
|
|
4
|
+
module RbNaCl
|
|
5
|
+
# Provides helpers for defining the libsodium bindings
|
|
6
|
+
module Sodium
|
|
7
|
+
def self.extended(klass)
|
|
8
|
+
klass.extend FFI::Library
|
|
9
|
+
klass.ffi_lib 'sodium'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def sodium_type(type = nil)
|
|
14
|
+
return @type if type.nil?
|
|
15
|
+
@type = type
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sodium_primitive(primitive = nil)
|
|
19
|
+
return @primitive if primitive.nil?
|
|
20
|
+
@primitive = primitive
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def primitive
|
|
24
|
+
sodium_primitive
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def sodium_constant(constant, name=constant)
|
|
28
|
+
fn = "crypto_#{sodium_type}_#{sodium_primitive}_#{constant.to_s.downcase}"
|
|
29
|
+
attach_function fn, [], :ulong_long
|
|
30
|
+
self.const_set(name, self.public_send(fn))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def sodium_function(name, function, arguments)
|
|
34
|
+
self.module_eval <<-eos, __FILE__, __LINE__ + 1
|
|
35
|
+
attach_function #{function.inspect}, #{arguments.inspect}, :int
|
|
36
|
+
def self.#{name}(*args)
|
|
37
|
+
ret = #{function}(*args)
|
|
38
|
+
ret == 0
|
|
39
|
+
end
|
|
40
|
+
eos
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/rbnacl/test_vectors.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
-
module
|
|
2
|
+
module RbNaCl
|
|
3
3
|
# Reference library of test vectors used to verify the software is correct
|
|
4
4
|
TestVectors = {
|
|
5
5
|
#
|
|
@@ -50,8 +50,41 @@ module Crypto
|
|
|
50
50
|
:sha256_message => "6162636462636465636465666465666765666768666768696768696a68696a6b" +
|
|
51
51
|
"696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071",
|
|
52
52
|
:sha256_digest => "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
|
|
53
|
+
:sha256_empty => "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
53
54
|
|
|
54
55
|
#
|
|
56
|
+
# SHA512 test vectors
|
|
57
|
+
# self-created (FIXME: find standard test vectors)
|
|
58
|
+
:sha512_message => "54686520717569636b2062726f776e20666f78206a756d7073206f7665722074" +
|
|
59
|
+
"6865206c617a7920646f672e",
|
|
60
|
+
:sha512_digest => "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bb" +
|
|
61
|
+
"c6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed",
|
|
62
|
+
:sha512_empty => "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" +
|
|
63
|
+
"47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
|
|
64
|
+
|
|
65
|
+
# Blake2b test vectors
|
|
66
|
+
# self-created? (TODO: double check, fix)
|
|
67
|
+
:blake2b_message => "54686520717569636b2062726f776e20666f78206a756d7073206f7665722074" +
|
|
68
|
+
"6865206c617a7920646f67",
|
|
69
|
+
:blake2b_digest => "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673" +
|
|
70
|
+
"f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918",
|
|
71
|
+
:blake2b_empty => "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419" +
|
|
72
|
+
"d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce",
|
|
73
|
+
|
|
74
|
+
# from the Blake2 paper(?) (TODO: double check)
|
|
75
|
+
:blake2b_keyed_message => "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
|
|
76
|
+
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
|
|
77
|
+
"404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
|
|
78
|
+
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
|
|
79
|
+
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
|
|
80
|
+
"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" +
|
|
81
|
+
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf" +
|
|
82
|
+
"e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe",
|
|
83
|
+
:blake2b_key => "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
|
|
84
|
+
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
|
|
85
|
+
:blake2b_keyed_digest => "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e9248" +
|
|
86
|
+
"4be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461",
|
|
87
|
+
|
|
55
88
|
# Auth test vectors
|
|
56
89
|
# Taken from NaCl distribution
|
|
57
90
|
#
|
data/lib/rbnacl/util.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# encoding: binary
|
|
2
|
-
module
|
|
2
|
+
module RbNaCl
|
|
3
3
|
# Various utility functions
|
|
4
4
|
module Util
|
|
5
|
+
extend Sodium
|
|
6
|
+
|
|
7
|
+
sodium_function :c_verify16, :crypto_verify_16, [:pointer, :pointer]
|
|
8
|
+
sodium_function :c_verify32, :crypto_verify_32, [:pointer, :pointer]
|
|
5
9
|
module_function
|
|
6
10
|
# Returns a string of n zeros
|
|
7
11
|
#
|
|
@@ -46,7 +50,7 @@ module Crypto
|
|
|
46
50
|
# In several places through the codebase we have to be VERY strict with
|
|
47
51
|
# what length of string we accept. This method supports that.
|
|
48
52
|
#
|
|
49
|
-
# @raise [
|
|
53
|
+
# @raise [RbNaCl::LengthError] If the string is not the right length
|
|
50
54
|
#
|
|
51
55
|
# @param string [String] The string to compare
|
|
52
56
|
# @param length [Integer] The desired length
|
|
@@ -57,7 +61,7 @@ module Crypto
|
|
|
57
61
|
"#{description} was nil (Expected #{length.to_int})",
|
|
58
62
|
caller
|
|
59
63
|
end
|
|
60
|
-
|
|
64
|
+
|
|
61
65
|
if string.bytesize != length.to_int
|
|
62
66
|
raise LengthError,
|
|
63
67
|
"#{description} was #{string.bytesize} bytes (Expected #{length.to_int})",
|
|
@@ -66,6 +70,27 @@ module Crypto
|
|
|
66
70
|
true
|
|
67
71
|
end
|
|
68
72
|
|
|
73
|
+
# Check a passed in string, converting the argument if necessary
|
|
74
|
+
#
|
|
75
|
+
# In several places through the codebase we have to be VERY strict with
|
|
76
|
+
# the strings we accept. This method supports that.
|
|
77
|
+
#
|
|
78
|
+
# @raise [ArgumentError] If we cannot convert to a string with #to_str
|
|
79
|
+
# @raise [RbNaCl::LengthError] If the string is not the right length
|
|
80
|
+
#
|
|
81
|
+
# @param string [#to_str] The input string
|
|
82
|
+
# @param length [Integer] The only acceptable length of the string
|
|
83
|
+
# @param description [String] Description of the string (used in the error)
|
|
84
|
+
def check_string(string, length, description)
|
|
85
|
+
unless string.respond_to? :to_str
|
|
86
|
+
raise TypeError, "can't convert #{string.class} into String with #to_str"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
string = string.to_str
|
|
90
|
+
check_length(string, length, description)
|
|
91
|
+
|
|
92
|
+
string
|
|
93
|
+
end
|
|
69
94
|
|
|
70
95
|
# Compare two 32 byte strings in constant time
|
|
71
96
|
#
|
|
@@ -79,7 +104,7 @@ module Crypto
|
|
|
79
104
|
# @return [Boolean] Well, are they equal?
|
|
80
105
|
def verify32(one, two)
|
|
81
106
|
return false unless two.bytesize == 32 && one.bytesize == 32
|
|
82
|
-
|
|
107
|
+
c_verify32(one, two)
|
|
83
108
|
end
|
|
84
109
|
|
|
85
110
|
# Compare two 32 byte strings in constant time
|
|
@@ -97,7 +122,7 @@ module Crypto
|
|
|
97
122
|
def verify32!(one, two)
|
|
98
123
|
check_length(one, 32, "First message")
|
|
99
124
|
check_length(two, 32, "Second message")
|
|
100
|
-
|
|
125
|
+
c_verify32(one, two)
|
|
101
126
|
end
|
|
102
127
|
|
|
103
128
|
# Compare two 16 byte strings in constant time
|
|
@@ -112,7 +137,7 @@ module Crypto
|
|
|
112
137
|
# @return [Boolean] Well, are they equal?
|
|
113
138
|
def verify16(one, two)
|
|
114
139
|
return false unless two.bytesize == 16 && one.bytesize == 16
|
|
115
|
-
|
|
140
|
+
c_verify16(one, two)
|
|
116
141
|
end
|
|
117
142
|
|
|
118
143
|
# Compare two 16 byte strings in constant time
|
|
@@ -130,7 +155,25 @@ module Crypto
|
|
|
130
155
|
def verify16!(one, two)
|
|
131
156
|
check_length(one, 16, "First message")
|
|
132
157
|
check_length(two, 16, "Second message")
|
|
133
|
-
|
|
158
|
+
c_verify16(one, two)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Hex encodes a message
|
|
162
|
+
#
|
|
163
|
+
# @param [String] bytes The bytes to encode
|
|
164
|
+
#
|
|
165
|
+
# @return [String] Tasty, tasty hexadecimal
|
|
166
|
+
def bin2hex(bytes)
|
|
167
|
+
bytes.to_s.unpack("H*").first
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Hex decodes a message
|
|
171
|
+
#
|
|
172
|
+
# @param [String] hex hex to decode.
|
|
173
|
+
#
|
|
174
|
+
# @return [String] crisp and clean bytes
|
|
175
|
+
def hex2bin(hex)
|
|
176
|
+
[hex.to_s].pack("H*")
|
|
134
177
|
end
|
|
135
178
|
end
|
|
136
179
|
end
|
data/lib/rbnacl/version.rb
CHANGED