rbnacl 3.3.0 → 3.4.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/.rubocop.yml +8 -3
- data/.travis.yml +11 -4
- data/CHANGES.md +10 -0
- data/Gemfile +6 -1
- data/README.md +5 -2
- data/lib/rbnacl.rb +2 -1
- data/lib/rbnacl/auth.rb +3 -3
- data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +6 -6
- data/lib/rbnacl/boxes/curve25519xsalsa20poly1305/private_key.rb +1 -1
- data/lib/rbnacl/hash.rb +2 -2
- data/lib/rbnacl/hash/blake2b.rb +5 -5
- data/lib/rbnacl/hmac/sha512.rb +42 -0
- data/lib/rbnacl/key_comparator.rb +13 -8
- data/lib/rbnacl/password_hash/scrypt.rb +38 -45
- data/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb +4 -4
- data/lib/rbnacl/self_test.rb +12 -12
- data/lib/rbnacl/signatures/ed25519/signing_key.rb +9 -1
- data/lib/rbnacl/signatures/ed25519/verify_key.rb +1 -1
- data/lib/rbnacl/simple_box.rb +2 -2
- data/lib/rbnacl/sodium/version.rb +2 -2
- data/lib/rbnacl/test_vectors.rb +7 -3
- data/lib/rbnacl/util.rb +9 -9
- data/lib/rbnacl/version.rb +1 -1
- data/spec/rbnacl/hmac/sha512_spec.rb +8 -0
- data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +5 -0
- data/spec/shared/authenticator.rb +5 -5
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcf4ccd28c18cf4c35fbdaf0b6a477e76611dde0
|
4
|
+
data.tar.gz: 9e6e95385b32259c3de1a5be583e20f910ba3f9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06843ef90fb734f7b2003adf225f78701682766c45fc5f786e4ee2e09347f7b3827df96fa14e39a3347eb097db168327f58e8867f483cbfd07fcc6dbb0870849
|
7
|
+
data.tar.gz: 5afb3ed48547db7e6883478654fe4c06065aa2fec84e43ce78d6f950d3cc439130039aad2eb34240bfe1026ed4939efa10878dc31ec5a0faadc67af6f6adfa5c
|
data/.rubocop.yml
CHANGED
@@ -9,7 +9,7 @@ LineLength:
|
|
9
9
|
Style/StringLiterals:
|
10
10
|
EnforcedStyle: double_quotes
|
11
11
|
|
12
|
-
Style/
|
12
|
+
Style/SpaceBeforeFirstArg:
|
13
13
|
Enabled: false
|
14
14
|
|
15
15
|
Style/GlobalVars:
|
@@ -20,8 +20,13 @@ Style/GlobalVars:
|
|
20
20
|
#
|
21
21
|
|
22
22
|
Metrics/MethodLength:
|
23
|
-
|
24
|
-
Max: 25
|
23
|
+
Max: 22
|
25
24
|
|
26
25
|
Metrics/AbcSize:
|
27
26
|
Max: 20
|
27
|
+
|
28
|
+
AllCops:
|
29
|
+
Include:
|
30
|
+
- '**/Rakefile'
|
31
|
+
Exclude:
|
32
|
+
- 'spec/**/*'
|
data/.travis.yml
CHANGED
@@ -1,13 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
1
3
|
script: bundle exec rake ci
|
4
|
+
branches:
|
5
|
+
only:
|
6
|
+
- master
|
7
|
+
|
8
|
+
bundler_args: --without development
|
2
9
|
|
3
10
|
rvm:
|
4
11
|
- 2.0.0
|
5
|
-
- 2.1.
|
6
|
-
- 2.2.
|
7
|
-
- 2.3.
|
12
|
+
- 2.1.10
|
13
|
+
- 2.2.5
|
14
|
+
- 2.3.1
|
8
15
|
- ruby-head
|
9
16
|
- jruby
|
10
|
-
- jruby-9.0.
|
17
|
+
- jruby-9.0.5.0
|
11
18
|
- jruby-head
|
12
19
|
- rbx-2
|
13
20
|
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
3.4.0 (2015-05-07)
|
2
|
+
------------------
|
3
|
+
* [#135](https://github.com/cryptosphere/rbnacl/pull/135)
|
4
|
+
Expose RbNaCl::Signatures::Ed25519#keypair_bytes.
|
5
|
+
(@grempe)
|
6
|
+
|
7
|
+
* [#137](https://github.com/cryptosphere/rbnacl/pull/137)
|
8
|
+
Expose HMAC-SHA512 (with 64-byte keys)
|
9
|
+
(@mwpastore)
|
10
|
+
|
1
11
|
3.3.0 (2015-12-29)
|
2
12
|
------------------
|
3
13
|
* [#105](https://github.com/cryptosphere/rbnacl/pull/105)
|
data/Gemfile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
# Specify your gem's dependencies in rbnacl.gemspec
|
4
3
|
gemspec
|
5
4
|
|
6
5
|
group :development do
|
@@ -8,6 +7,12 @@ group :development do
|
|
8
7
|
end
|
9
8
|
|
10
9
|
group :test do
|
10
|
+
gem "rspec"
|
11
|
+
gem "rubocop", "0.39.0"
|
11
12
|
gem "coveralls", require: false
|
12
13
|
gem "rbnacl-libsodium", ENV["LIBSODIUM_VERSION"]
|
13
14
|
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "rake"
|
18
|
+
end
|
data/README.md
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
[](https://travis-ci.org/cryptosphere/rbnacl)
|
5
5
|
[](https://codeclimate.com/github/cryptosphere/rbnacl)
|
6
6
|
[](https://coveralls.io/r/cryptosphere/rbnacl)
|
7
|
+
[](https://github.com/cryptosphere/rbnacl/blob/master/LICENSE.txt)
|
7
8
|
|
8
9
|
A Ruby binding to the state-of-the-art [Networking and Cryptography][nacl]
|
9
10
|
library by [Daniel J. Bernstein][djb]. This is **NOT** Google Native Client.
|
@@ -71,6 +72,8 @@ To use RbNaCl, you will need to install libsodium:
|
|
71
72
|
|
72
73
|
https://github.com/jedisct1/libsodium
|
73
74
|
|
75
|
+
At least version `1.0.0` is recommended.
|
76
|
+
|
74
77
|
For OS X users, libsodium is available via homebrew and can be installed with:
|
75
78
|
|
76
79
|
brew install libsodium
|
@@ -195,5 +198,5 @@ Sure, here you go:
|
|
195
198
|
|
196
199
|
## License
|
197
200
|
|
198
|
-
Copyright (c) 2012-
|
199
|
-
|
201
|
+
Copyright (c) 2012-2016 Jonathan Stott, Tony Arcieri. Distributed under the MIT License.
|
202
|
+
See LICENSE.txt for further details.
|
data/lib/rbnacl.rb
CHANGED
@@ -67,9 +67,10 @@ module RbNaCl
|
|
67
67
|
require "rbnacl/password_hash"
|
68
68
|
require "rbnacl/password_hash/scrypt"
|
69
69
|
|
70
|
-
# HMAC: SHA256 and SHA512256
|
70
|
+
# HMAC: SHA256/512 and SHA512256
|
71
71
|
require "rbnacl/hmac/sha256"
|
72
72
|
require "rbnacl/hmac/sha512256"
|
73
|
+
require "rbnacl/hmac/sha512"
|
73
74
|
|
74
75
|
#
|
75
76
|
# Bind aliases used by the public API
|
data/lib/rbnacl/auth.rb
CHANGED
@@ -70,7 +70,7 @@ module RbNaCl
|
|
70
70
|
def verify(authenticator, message)
|
71
71
|
auth = authenticator.to_s
|
72
72
|
Util.check_length(auth, tag_bytes, "Provided authenticator")
|
73
|
-
verify_message(auth, message) ||
|
73
|
+
verify_message(auth, message) || raise(BadAuthenticatorError, "Invalid authenticator provided, message is corrupt")
|
74
74
|
end
|
75
75
|
|
76
76
|
# The crypto primitive for this authenticator instance
|
@@ -111,11 +111,11 @@ module RbNaCl
|
|
111
111
|
private
|
112
112
|
|
113
113
|
def compute_authenticator(_authenticator, _message)
|
114
|
-
|
114
|
+
raise NotImplementedError
|
115
115
|
end
|
116
116
|
|
117
117
|
def verify_message(_authenticator, _message)
|
118
|
-
|
118
|
+
raise NotImplementedError
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
@@ -99,7 +99,7 @@ module RbNaCl
|
|
99
99
|
def initialize(public_key, private_key)
|
100
100
|
@public_key = public_key.is_a?(PublicKey) ? public_key : PublicKey.new(public_key)
|
101
101
|
@private_key = private_key.is_a?(PrivateKey) ? private_key : PrivateKey.new(private_key)
|
102
|
-
|
102
|
+
raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
|
103
103
|
end
|
104
104
|
|
105
105
|
# Encrypts a message
|
@@ -121,10 +121,10 @@ module RbNaCl
|
|
121
121
|
msg = Util.prepend_zeros(ZEROBYTES, message)
|
122
122
|
ct = Util.zeros(msg.bytesize)
|
123
123
|
|
124
|
-
self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) ||
|
124
|
+
self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
|
125
125
|
Util.remove_zeros(BOXZEROBYTES, ct)
|
126
126
|
end
|
127
|
-
|
127
|
+
alias encrypt box
|
128
128
|
|
129
129
|
# Decrypts a ciphertext
|
130
130
|
#
|
@@ -146,11 +146,11 @@ module RbNaCl
|
|
146
146
|
message = Util.zeros(ct.bytesize)
|
147
147
|
|
148
148
|
success = self.class.box_curve25519xsalsa20poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm)
|
149
|
-
|
149
|
+
raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success
|
150
150
|
|
151
151
|
Util.remove_zeros(ZEROBYTES, message)
|
152
152
|
end
|
153
|
-
|
153
|
+
alias decrypt open
|
154
154
|
|
155
155
|
# The crypto primitive for the box class
|
156
156
|
#
|
@@ -179,7 +179,7 @@ module RbNaCl
|
|
179
179
|
@_key ||= begin
|
180
180
|
key = Util.zeros(BEFORENMBYTES)
|
181
181
|
success = self.class.box_curve25519xsalsa20poly1305_beforenm(key, @public_key.to_s, @private_key.to_s)
|
182
|
-
|
182
|
+
raise CryptoError, "Failed to derive shared key" unless success
|
183
183
|
key
|
184
184
|
end
|
185
185
|
end
|
@@ -52,7 +52,7 @@ module RbNaCl
|
|
52
52
|
def self.generate
|
53
53
|
pk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PUBLICKEYBYTES)
|
54
54
|
sk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES)
|
55
|
-
box_curve25519xsalsa20poly1305_keypair(pk, sk) ||
|
55
|
+
box_curve25519xsalsa20poly1305_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair")
|
56
56
|
new(sk)
|
57
57
|
end
|
58
58
|
|
data/lib/rbnacl/hash.rb
CHANGED
@@ -25,7 +25,7 @@ module RbNaCl
|
|
25
25
|
def self.sha256(data)
|
26
26
|
data = data.to_str
|
27
27
|
digest = Util.zeros(SHA256::BYTES)
|
28
|
-
SHA256.hash_sha256(digest, data, data.bytesize) ||
|
28
|
+
SHA256.hash_sha256(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
|
29
29
|
digest
|
30
30
|
end
|
31
31
|
|
@@ -40,7 +40,7 @@ module RbNaCl
|
|
40
40
|
# @return [String] The SHA-512 hash digest as raw bytes
|
41
41
|
def self.sha512(data)
|
42
42
|
digest = Util.zeros(SHA512::BYTES)
|
43
|
-
SHA512.hash_sha512(digest, data, data.bytesize) ||
|
43
|
+
SHA512.hash_sha512(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
|
44
44
|
digest
|
45
45
|
end
|
46
46
|
|
data/lib/rbnacl/hash/blake2b.rb
CHANGED
@@ -47,15 +47,15 @@ module RbNaCl
|
|
47
47
|
|
48
48
|
if @key
|
49
49
|
@key_size = @key.bytesize
|
50
|
-
|
51
|
-
|
50
|
+
raise LengthError, "key too short" if @key_size < KEYBYTES_MIN
|
51
|
+
raise LengthError, "key too long" if @key_size > KEYBYTES_MAX
|
52
52
|
else
|
53
53
|
@key_size = 0
|
54
54
|
end
|
55
55
|
|
56
56
|
@digest_size = opts.fetch(:digest_size, BYTES_MAX)
|
57
|
-
|
58
|
-
|
57
|
+
raise LengthError, "digest size too short" if @digest_size < BYTES_MIN
|
58
|
+
raise LengthError, "digest size too long" if @digest_size > BYTES_MAX
|
59
59
|
|
60
60
|
@personal = opts.fetch(:personal, EMPTY_PERSONAL)
|
61
61
|
@personal = Util.zero_pad(PERSONALBYTES, @personal)
|
@@ -72,7 +72,7 @@ module RbNaCl
|
|
72
72
|
def digest(message)
|
73
73
|
digest = Util.zeros(@digest_size)
|
74
74
|
self.class.generichash_blake2b(digest, @digest_size, message, message.bytesize, @key, @key_size, @salt, @personal) ||
|
75
|
-
|
75
|
+
raise(CryptoError, "Hashing failed!")
|
76
76
|
digest
|
77
77
|
end
|
78
78
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
module RbNaCl
|
3
|
+
module HMAC
|
4
|
+
# Computes an authenticator as HMAC-SHA-512
|
5
|
+
#
|
6
|
+
# The authenticator can be used at a later time to verify the provenance of
|
7
|
+
# the message by recomputing the HMAC over the message and then comparing it to
|
8
|
+
# the provided authenticator. The class provides methods for generating
|
9
|
+
# signatures and also has a constant-time implementation for checking them.
|
10
|
+
#
|
11
|
+
# This is a secret key authenticator, i.e. anyone who can verify signatures
|
12
|
+
# can also create them.
|
13
|
+
#
|
14
|
+
# @see http://nacl.cr.yp.to/auth.html
|
15
|
+
class SHA512 < Auth
|
16
|
+
extend Sodium
|
17
|
+
|
18
|
+
sodium_type :auth
|
19
|
+
sodium_primitive :hmacsha512
|
20
|
+
sodium_constant :BYTES
|
21
|
+
sodium_constant :KEYBYTES
|
22
|
+
|
23
|
+
sodium_function :auth_hmacsha512,
|
24
|
+
:crypto_auth_hmacsha512,
|
25
|
+
[:pointer, :pointer, :ulong_long, :pointer]
|
26
|
+
|
27
|
+
sodium_function :auth_hmacsha512_verify,
|
28
|
+
:crypto_auth_hmacsha512_verify,
|
29
|
+
[:pointer, :pointer, :ulong_long, :pointer]
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def compute_authenticator(authenticator, message)
|
34
|
+
self.class.auth_hmacsha512(authenticator, message, message.bytesize, key)
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify_message(authenticator, message)
|
38
|
+
self.class.auth_hmacsha512_verify(authenticator, message, message.bytesize, key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -22,14 +22,7 @@ module RbNaCl
|
|
22
22
|
else
|
23
23
|
return nil
|
24
24
|
end
|
25
|
-
|
26
|
-
if Util.verify32(to_bytes, other)
|
27
|
-
return 0
|
28
|
-
elsif to_bytes > other
|
29
|
-
return 1
|
30
|
-
else
|
31
|
-
return -1
|
32
|
-
end
|
25
|
+
compare32(other)
|
33
26
|
end
|
34
27
|
|
35
28
|
# equality operator
|
@@ -55,5 +48,17 @@ module RbNaCl
|
|
55
48
|
end
|
56
49
|
Util.verify32(to_bytes, other)
|
57
50
|
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def compare32(other)
|
55
|
+
if Util.verify32(to_bytes, other)
|
56
|
+
0
|
57
|
+
elsif to_bytes > other
|
58
|
+
1
|
59
|
+
else
|
60
|
+
-1
|
61
|
+
end
|
62
|
+
end
|
58
63
|
end
|
59
64
|
end
|
@@ -17,52 +17,45 @@ module RbNaCl
|
|
17
17
|
# on GPUs or FPGAs) with additional computation.
|
18
18
|
class SCrypt
|
19
19
|
extend Sodium
|
20
|
+
sodium_type :pwhash
|
21
|
+
sodium_primitive :scryptsalsa208sha256
|
22
|
+
|
23
|
+
sodium_constant :SALTBYTES
|
24
|
+
|
25
|
+
sodium_function :scrypt,
|
26
|
+
:crypto_pwhash_scryptsalsa208sha256,
|
27
|
+
[:pointer, :ulong_long, :pointer, :ulong_long, :pointer, :ulong_long, :size_t]
|
28
|
+
|
29
|
+
# Create a new SCrypt password hash object
|
30
|
+
#
|
31
|
+
# @param [Integer] opslimit the CPU cost (e.g. 2**20)
|
32
|
+
# @param [Integer] memlimit the memory cost (e.g. 2**24)
|
33
|
+
#
|
34
|
+
# @return [RbNaCl::PasswordHash::SCrypt] An SCrypt password hasher object
|
35
|
+
def initialize(opslimit, memlimit, digest_size = 64)
|
36
|
+
# TODO: sanity check these parameters
|
37
|
+
@opslimit = opslimit
|
38
|
+
@memlimit = memlimit
|
39
|
+
|
40
|
+
# TODO: check digest size validity
|
41
|
+
# raise LengthError, "digest size too short" if @digest_size < BYTES_MIN
|
42
|
+
# raise LengthError, "digest size too long" if @digest_size > BYTES_MAX
|
43
|
+
|
44
|
+
@digest_size = digest_size
|
45
|
+
end
|
20
46
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# @param [Integer] opslimit the CPU cost (e.g. 2**20)
|
34
|
-
# @param [Integer] memlimit the memory cost (e.g. 2**24)
|
35
|
-
#
|
36
|
-
# @return [RbNaCl::PasswordHash::SCrypt] An SCrypt password hasher object
|
37
|
-
def initialize(opslimit, memlimit, digest_size = 64)
|
38
|
-
# TODO: sanity check these parameters
|
39
|
-
@opslimit = opslimit
|
40
|
-
@memlimit = memlimit
|
41
|
-
|
42
|
-
# TODO: check digest size validity
|
43
|
-
# raise LengthError, "digest size too short" if @digest_size < BYTES_MIN
|
44
|
-
# raise LengthError, "digest size too long" if @digest_size > BYTES_MAX
|
45
|
-
|
46
|
-
@digest_size = digest_size
|
47
|
-
end
|
48
|
-
|
49
|
-
# Calculate an scrypt digest for a given password and salt
|
50
|
-
#
|
51
|
-
# @param [String] password to be hashed
|
52
|
-
# @param [String] salt to make the digest unique
|
53
|
-
#
|
54
|
-
# @return [String] scrypt digest of the string as raw bytes
|
55
|
-
def digest(password, salt)
|
56
|
-
digest = Util.zeros(@digest_size)
|
57
|
-
salt = Util.check_string(salt, SALTBYTES, "salt")
|
58
|
-
|
59
|
-
self.class.scrypt(digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit) || fail(CryptoError, "scrypt failed!")
|
60
|
-
digest
|
61
|
-
end
|
62
|
-
rescue FFI::NotFoundError
|
63
|
-
def initialize(_opslimit, _memlimit, _digest_size = 64)
|
64
|
-
raise NotImplementedError, "scrypt not implemented in this version of libsodium"
|
65
|
-
end
|
47
|
+
# Calculate an scrypt digest for a given password and salt
|
48
|
+
#
|
49
|
+
# @param [String] password to be hashed
|
50
|
+
# @param [String] salt to make the digest unique
|
51
|
+
#
|
52
|
+
# @return [String] scrypt digest of the string as raw bytes
|
53
|
+
def digest(password, salt)
|
54
|
+
digest = Util.zeros(@digest_size)
|
55
|
+
salt = Util.check_string(salt, SALTBYTES, "salt")
|
56
|
+
|
57
|
+
self.class.scrypt(digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit) || raise(CryptoError, "scrypt failed!")
|
58
|
+
digest
|
66
59
|
end
|
67
60
|
end
|
68
61
|
end
|
@@ -68,11 +68,11 @@ module RbNaCl
|
|
68
68
|
ct = Util.zeros(msg.bytesize)
|
69
69
|
|
70
70
|
success = self.class.secretbox_xsalsa20poly1305(ct, msg, msg.bytesize, nonce, @key)
|
71
|
-
|
71
|
+
raise CryptoError, "Encryption failed" unless success
|
72
72
|
|
73
73
|
Util.remove_zeros(BOXZEROBYTES, ct)
|
74
74
|
end
|
75
|
-
|
75
|
+
alias encrypt box
|
76
76
|
|
77
77
|
# Decrypts a ciphertext
|
78
78
|
#
|
@@ -94,11 +94,11 @@ module RbNaCl
|
|
94
94
|
message = Util.zeros(ct.bytesize)
|
95
95
|
|
96
96
|
success = self.class.secretbox_xsalsa20poly1305_open(message, ct, ct.bytesize, nonce, @key)
|
97
|
-
|
97
|
+
raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success
|
98
98
|
|
99
99
|
Util.remove_zeros(ZEROBYTES, message)
|
100
100
|
end
|
101
|
-
|
101
|
+
alias decrypt open
|
102
102
|
|
103
103
|
# The crypto primitive for the SecretBox instance
|
104
104
|
#
|
data/lib/rbnacl/self_test.rb
CHANGED
@@ -32,8 +32,8 @@ module RbNaCl
|
|
32
32
|
message = vector :box_message
|
33
33
|
ciphertext = vector :box_ciphertext
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
raise SelfTestFailure, "failed to generate correct ciphertext" unless box.encrypt(nonce, message) == ciphertext
|
36
|
+
raise SelfTestFailure, "failed to decrypt ciphertext correctly" unless box.decrypt(nonce, ciphertext) == message
|
37
37
|
|
38
38
|
begin
|
39
39
|
passed = false
|
@@ -43,7 +43,7 @@ module RbNaCl
|
|
43
43
|
rescue CryptoError
|
44
44
|
passed = true
|
45
45
|
ensure
|
46
|
-
passed ||
|
46
|
+
passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -53,7 +53,7 @@ module RbNaCl
|
|
53
53
|
|
54
54
|
unless verify_key.to_s == vector(:sign_public)
|
55
55
|
#:nocov:
|
56
|
-
|
56
|
+
raise SelfTestFailure, "failed to generate verify key correctly"
|
57
57
|
#:nocov:
|
58
58
|
end
|
59
59
|
|
@@ -62,13 +62,13 @@ module RbNaCl
|
|
62
62
|
|
63
63
|
unless signature == vector(:sign_signature)
|
64
64
|
#:nocov:
|
65
|
-
|
65
|
+
raise SelfTestFailure, "failed to generate correct signature"
|
66
66
|
#:nocov:
|
67
67
|
end
|
68
68
|
|
69
69
|
unless verify_key.verify(signature, message)
|
70
70
|
#:nocov:
|
71
|
-
|
71
|
+
raise SelfTestFailure, "failed to verify a valid signature"
|
72
72
|
#:nocov:
|
73
73
|
end
|
74
74
|
|
@@ -79,7 +79,7 @@ module RbNaCl
|
|
79
79
|
rescue CryptoError
|
80
80
|
passed = true
|
81
81
|
ensure
|
82
|
-
passed ||
|
82
|
+
passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext")
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -87,16 +87,16 @@ module RbNaCl
|
|
87
87
|
message = vector :sha256_message
|
88
88
|
digest = vector :sha256_digest
|
89
89
|
|
90
|
-
|
90
|
+
raise SelfTestFailure, "failed to generate a correct SHA256 digest" unless RbNaCl::Hash.sha256(message) == digest
|
91
91
|
end
|
92
92
|
|
93
93
|
def hmac_test(klass, tag)
|
94
|
-
authenticator = klass.new(vector(
|
94
|
+
authenticator = klass.new(vector("auth_key_#{klass.key_bytes}".to_sym))
|
95
95
|
|
96
96
|
message = vector :auth_message
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
raise SelfTestFailure, "#{klass} failed to generate correct authentication tag" unless authenticator.auth(message) == vector(tag)
|
99
|
+
raise SelfTestFailure, "#{klass} failed to verify correct authentication tag" unless authenticator.verify(vector(tag), message)
|
100
100
|
|
101
101
|
begin
|
102
102
|
passed = false
|
@@ -104,7 +104,7 @@ module RbNaCl
|
|
104
104
|
rescue CryptoError
|
105
105
|
passed = true
|
106
106
|
ensure
|
107
|
-
passed ||
|
107
|
+
passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext")
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
@@ -58,7 +58,7 @@ module RbNaCl
|
|
58
58
|
pk = Util.zeros(Ed25519::VERIFYKEYBYTES)
|
59
59
|
sk = Util.zeros(Ed25519::SIGNINGKEYBYTES)
|
60
60
|
|
61
|
-
self.class.sign_ed25519_seed_keypair(pk, sk, seed) ||
|
61
|
+
self.class.sign_ed25519_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair")
|
62
62
|
|
63
63
|
@seed = seed
|
64
64
|
@signing_key = sk
|
@@ -86,6 +86,14 @@ module RbNaCl
|
|
86
86
|
@seed
|
87
87
|
end
|
88
88
|
|
89
|
+
# Return the raw 64 byte value of this key
|
90
|
+
#
|
91
|
+
# @return [String] The signature key bytes. Left half is 32-byte
|
92
|
+
# curve25519 private scalar, right half is 32-byte group element
|
93
|
+
def keypair_bytes
|
94
|
+
@signing_key
|
95
|
+
end
|
96
|
+
|
89
97
|
# The crypto primitive this SigningKey class uses for signatures
|
90
98
|
#
|
91
99
|
# @return [Symbol] The primitive
|
@@ -51,7 +51,7 @@ module RbNaCl
|
|
51
51
|
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)
|
52
52
|
|
53
53
|
success = self.class.sign_ed25519_open(buffer, buffer_len, sig_and_msg, sig_and_msg.bytesize, @key)
|
54
|
-
|
54
|
+
raise(BadSignatureError, "signature was forged/corrupt") unless success
|
55
55
|
|
56
56
|
true
|
57
57
|
end
|
data/lib/rbnacl/simple_box.rb
CHANGED
@@ -80,7 +80,7 @@ module RbNaCl
|
|
80
80
|
cipher_text = @box.box(nonce, message)
|
81
81
|
nonce + cipher_text
|
82
82
|
end
|
83
|
-
|
83
|
+
alias encrypt box
|
84
84
|
|
85
85
|
# Decrypts the ciphertext with a random nonce
|
86
86
|
#
|
@@ -96,7 +96,7 @@ module RbNaCl
|
|
96
96
|
nonce, ciphertext = extract_nonce(enciphered_message.to_s)
|
97
97
|
@box.open(nonce, ciphertext)
|
98
98
|
end
|
99
|
-
|
99
|
+
alias decrypt open
|
100
100
|
|
101
101
|
private
|
102
102
|
|
@@ -4,7 +4,7 @@ module RbNaCl
|
|
4
4
|
module Sodium
|
5
5
|
# libsodium version API
|
6
6
|
module Version
|
7
|
-
MINIMUM_LIBSODIUM_VERSION = "0.4.3"
|
7
|
+
MINIMUM_LIBSODIUM_VERSION = "0.4.3".freeze
|
8
8
|
|
9
9
|
extend Sodium
|
10
10
|
attach_function :sodium_version_string, [], :string
|
@@ -17,7 +17,7 @@ module RbNaCl
|
|
17
17
|
|
18
18
|
case installed_version <=> minimum_version
|
19
19
|
when -1
|
20
|
-
|
20
|
+
raise "Sorry, you need to install libsodium #{MINIMUM_LIBSODIUM_VERSION}+. You have #{Version::STRING} installed"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/lib/rbnacl/test_vectors.rb
CHANGED
@@ -122,7 +122,9 @@ module RbNaCl
|
|
122
122
|
# Auth test vectors
|
123
123
|
# Taken from NaCl distribution
|
124
124
|
#
|
125
|
-
|
125
|
+
auth_key_32: "eea6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff880",
|
126
|
+
auth_key_64: "eaaa4c73ef13e7e9a53011304c5be141da9c3713b5ca822037ed57aded31b70a" \
|
127
|
+
"50a0dd80843d580fe5b57e470bb534333e907a624cf02873c6b9eaba70e0fc7e",
|
126
128
|
auth_message: "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a" \
|
127
129
|
"c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738" \
|
128
130
|
"b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da" \
|
@@ -131,6 +133,8 @@ module RbNaCl
|
|
131
133
|
auth_onetime: "f3ffc7703f9400e52a7dfb4b3d3305d9",
|
132
134
|
# self-created (FIXME: find standard test vectors)
|
133
135
|
auth_hmacsha256: "7f7b9b707e8790ca8620ff94df5e6533ddc8e994060ce310c9d7de04d44aabc3",
|
134
|
-
auth_hmacsha512256: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d"
|
135
|
-
|
136
|
+
auth_hmacsha512256: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d",
|
137
|
+
auth_hmacsha512: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d" \
|
138
|
+
"270e3921f69016c267a63ab4b226449a0dee0dc7dcb897a9bce9d27d788f8e8d"
|
139
|
+
}.freeze
|
136
140
|
end
|
data/lib/rbnacl/util.rb
CHANGED
@@ -60,7 +60,7 @@ module RbNaCl
|
|
60
60
|
if len == n
|
61
61
|
message
|
62
62
|
elsif len > n
|
63
|
-
|
63
|
+
raise LengthError, "String too long for zero-padding to #{n} bytes"
|
64
64
|
else
|
65
65
|
message + zeros(n - len)
|
66
66
|
end
|
@@ -78,15 +78,15 @@ module RbNaCl
|
|
78
78
|
# @param description [String] Description of the string (used in the error)
|
79
79
|
def check_length(string, length, description)
|
80
80
|
if string.nil?
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
raise LengthError,
|
82
|
+
"#{description} was nil (Expected #{length.to_int})",
|
83
|
+
caller
|
84
84
|
end
|
85
85
|
|
86
86
|
if string.bytesize != length.to_int
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
raise LengthError,
|
88
|
+
"#{description} was #{string.bytesize} bytes (Expected #{length.to_int})",
|
89
|
+
caller
|
90
90
|
end
|
91
91
|
true
|
92
92
|
end
|
@@ -104,12 +104,12 @@ module RbNaCl
|
|
104
104
|
# @param description [String] Description of the string (used in the error)
|
105
105
|
def check_string(string, length, description)
|
106
106
|
unless string.respond_to? :to_str
|
107
|
-
|
107
|
+
raise TypeError, "can't convert #{string.class} into String with #to_str"
|
108
108
|
end
|
109
109
|
|
110
110
|
string = string.to_str
|
111
111
|
unless string.encoding == Encoding::BINARY
|
112
|
-
|
112
|
+
raise EncodingError, "strings must use BINARY encoding (got #{string.encoding})"
|
113
113
|
end
|
114
114
|
check_length(string, length, description)
|
115
115
|
|
data/lib/rbnacl/version.rb
CHANGED
@@ -20,6 +20,11 @@ RSpec.describe RbNaCl::SigningKey do
|
|
20
20
|
expect(subject.to_bytes).to eq signing_key
|
21
21
|
end
|
22
22
|
|
23
|
+
it "serializes the internal signing key to bytes" do
|
24
|
+
expect(subject.keypair_bytes.length).to eq 64
|
25
|
+
expect(subject.keypair_bytes).to eq "\xB1\x8E\x1D\x00E\x99^\xC3\xD0\x10\xC3\x87\xCC\xFE\xB9\x84\xD7\x83\xAF\x8F\xBB\x0F@\xFA}\xB1&\xD8\x89\xF6\xDA\xDDw\xF4\x8BY\xCA\xED\xA7wQ\xED\x13\x8B\x0E\xC6g\xFFP\xF8v\x8C%\xD4\x83\t\xA8\xF3\x86\xA2\xBA\xD1\x87\xFB"
|
26
|
+
end
|
27
|
+
|
23
28
|
include_examples "key equality" do
|
24
29
|
let(:key_bytes) { signing_key }
|
25
30
|
let(:key) { described_class.new(key_bytes) }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: binary
|
2
2
|
RSpec.shared_examples "authenticator" do
|
3
|
-
let(:key) { vector
|
3
|
+
let(:key) { vector "auth_key_#{described_class.key_bytes}".to_sym }
|
4
4
|
let(:message) { vector :auth_message }
|
5
5
|
|
6
6
|
context ".new" do
|
@@ -17,11 +17,11 @@ RSpec.shared_examples "authenticator" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "raises ArgumentError on a key which is too long" do
|
20
|
-
expect { described_class.new("\0" *
|
20
|
+
expect { described_class.new("\0" * described_class.key_bytes.succ) }.to raise_error(ArgumentError)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "raises ArgumentError on a key which is too short" do
|
24
|
-
expect { described_class.new("\0" *
|
24
|
+
expect { described_class.new("\0" * described_class.key_bytes.pred) }.to raise_error(ArgumentError)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -35,7 +35,7 @@ RSpec.shared_examples "authenticator" do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it "raises ArgumentError on a key which is too long" do
|
38
|
-
expect { described_class.auth("\0" *
|
38
|
+
expect { described_class.auth("\0" * described_class.key_bytes.succ, message) }.to raise_error(ArgumentError)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -49,7 +49,7 @@ RSpec.shared_examples "authenticator" do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it "raises ArgumentError on a key which is too long" do
|
52
|
-
expect { described_class.verify("\0" *
|
52
|
+
expect { described_class.verify("\0" * described_class.key_bytes.succ, tag, message) }.to raise_error(ArgumentError)
|
53
53
|
end
|
54
54
|
|
55
55
|
it "fails to validate an invalid authenticator" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbnacl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain:
|
12
12
|
- bascule.cert
|
13
|
-
date:
|
13
|
+
date: 2016-05-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: ffi
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- lib/rbnacl/hash/sha256.rb
|
106
106
|
- lib/rbnacl/hash/sha512.rb
|
107
107
|
- lib/rbnacl/hmac/sha256.rb
|
108
|
+
- lib/rbnacl/hmac/sha512.rb
|
108
109
|
- lib/rbnacl/hmac/sha512256.rb
|
109
110
|
- lib/rbnacl/init.rb
|
110
111
|
- lib/rbnacl/key_comparator.rb
|
@@ -134,6 +135,7 @@ files:
|
|
134
135
|
- spec/rbnacl/hash_spec.rb
|
135
136
|
- spec/rbnacl/hmac/sha256_spec.rb
|
136
137
|
- spec/rbnacl/hmac/sha512256_spec.rb
|
138
|
+
- spec/rbnacl/hmac/sha512_spec.rb
|
137
139
|
- spec/rbnacl/password_hash/scrypt_spec.rb
|
138
140
|
- spec/rbnacl/random_spec.rb
|
139
141
|
- spec/rbnacl/secret_box_spec.rb
|
@@ -183,6 +185,7 @@ test_files:
|
|
183
185
|
- spec/rbnacl/hash_spec.rb
|
184
186
|
- spec/rbnacl/hmac/sha256_spec.rb
|
185
187
|
- spec/rbnacl/hmac/sha512256_spec.rb
|
188
|
+
- spec/rbnacl/hmac/sha512_spec.rb
|
186
189
|
- spec/rbnacl/password_hash/scrypt_spec.rb
|
187
190
|
- spec/rbnacl/random_spec.rb
|
188
191
|
- spec/rbnacl/secret_box_spec.rb
|
@@ -195,4 +198,3 @@ test_files:
|
|
195
198
|
- spec/shared/key_equality.rb
|
196
199
|
- spec/shared/serializable.rb
|
197
200
|
- spec/spec_helper.rb
|
198
|
-
has_rdoc:
|