rbnacl 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/cryptosphere/rbnacl.svg?branch=master)](https://travis-ci.org/cryptosphere/rbnacl)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/cryptosphere/rbnacl.svg)](https://codeclimate.com/github/cryptosphere/rbnacl)
|
6
6
|
[![Coverage Status](https://coveralls.io/repos/cryptosphere/rbnacl/badge.svg?branch=master)](https://coveralls.io/r/cryptosphere/rbnacl)
|
7
|
+
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](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:
|