rbnacl 4.0.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06b62936ca905b101e22418710c37dfc78cd5d11
4
- data.tar.gz: 0b8b8ba5efb7e6673bb8811e19695a7fbb714fbd
3
+ metadata.gz: 0ff080260ca84ccc368c7c8414627267dffa9348
4
+ data.tar.gz: 2a3275a27b2ca89e36223529316076b67f895cac
5
5
  SHA512:
6
- metadata.gz: 69a6b4e5aaeee71020409df122943399ba64c1b46a76c4a75b4abaf113fb6d3d93c553f128f8b42e2a52d57a7e8081e45749b6c585b6aca434cbda1eea972fb7
7
- data.tar.gz: 20d228a8f6a56e5c710288fb6e73b16ad39d0185f369bd29b519f8742c1da1b5523388ea6bdfea8e1d21df892019761cc99e6e920f44bfdae8e671fa2cb00fe3
6
+ metadata.gz: 32bd4e83ea75ce57d93dcc7c1b2f3249d7e0010694c03d7d9a73a20e1a310ec6b9b6f40e0f190fb454f64eda528ea4e7eb35367d49d04f5ea7aafad270d26ff2
7
+ data.tar.gz: 9408f5ae9713e018e29a943bb9ddbb64010e9ace49d4cff37b2769e886f09025edba7776dcfbe81372363051b8d7b68cd7e04a583b8eeda87b3d48a17f39607b
@@ -35,3 +35,6 @@ Style/SpaceBeforeFirstArg:
35
35
 
36
36
  Style/GlobalVars:
37
37
  Enabled: false
38
+
39
+ Style/SafeNavigation:
40
+ Enabled: false
data/CHANGES.md CHANGED
@@ -1,4 +1,10 @@
1
- ## 4.0.2 (2016-03-12)
1
+ ## 5.0.0 (2017-06-13)
2
+
3
+ * [#159](https://github.com/cryptosphere/rbnacl/pull/159)
4
+ Support the BLAKE2b Initialize-Update-Finalize API.
5
+ ([@fudanchii])
6
+
7
+ ## 4.0.2 (2017-03-12)
2
8
 
3
9
  * [#157](https://github.com/cryptosphere/rbnacl/pull/157)
4
10
  Raise error on degenerate keys (fixes #152).
@@ -112,3 +118,4 @@
112
118
  [@mwpastore]: https://github.com/mwpastore
113
119
  [@elijh]: https://github.com/elijh
114
120
  [@paragonie-scott]: https://github.com/paragonie-scott
121
+ [@fudanchii]: https://github.com/fudanchii
data/README.md CHANGED
@@ -6,10 +6,10 @@
6
6
  [![Coverage Status](https://coveralls.io/repos/cryptosphere/rbnacl/badge.svg?branch=master)](https://coveralls.io/r/cryptosphere/rbnacl)
7
7
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/cryptosphere/rbnacl/blob/master/LICENSE.txt)
8
8
 
9
- _NOTE: This is the 4.x **stable** branch of RbNaCl. For the 3.x **legacy**
9
+ _NOTE: This is the 5.x **stable** branch of RbNaCl. For the 4.x **legacy**
10
10
  branch, please see:_
11
11
 
12
- https://github.com/cryptosphere/rbnacl/tree/3-x-stable
12
+ https://github.com/cryptosphere/rbnacl/tree/4-x-stable
13
13
 
14
14
  A Ruby binding to the state-of-the-art [Networking and Cryptography][nacl]
15
15
  library by [Daniel J. Bernstein][djb]. This is **NOT** Google Native Client.
@@ -63,7 +63,7 @@ module RbNaCl
63
63
  #
64
64
  # @return [String] The Blake2b hash digest as raw bytes
65
65
  def self.blake2b(data, options = {})
66
- Blake2b.new(options).digest(data)
66
+ Blake2b.digest(data, options)
67
67
  end
68
68
  end
69
69
  end
@@ -28,12 +28,25 @@ module RbNaCl
28
28
  :crypto_generichash_blake2b_salt_personal,
29
29
  [:pointer, :size_t, :pointer, :ulong_long, :pointer, :size_t, :pointer, :pointer]
30
30
 
31
+ sodium_function :generichash_blake2b_init,
32
+ :crypto_generichash_blake2b_init_salt_personal,
33
+ [:pointer, :pointer, :size_t, :size_t, :pointer, :pointer]
34
+
35
+ sodium_function :generichash_blake2b_update,
36
+ :crypto_generichash_blake2b_update,
37
+ [:pointer, :pointer, :ulong_long]
38
+
39
+ sodium_function :generichash_blake2b_final,
40
+ :crypto_generichash_blake2b_final,
41
+ [:pointer, :pointer, :size_t]
42
+
31
43
  EMPTY_PERSONAL = ("\0" * PERSONALBYTES).freeze
32
44
  EMPTY_SALT = ("\0" * SALTBYTES).freeze
33
45
 
34
- # Create a new Blake2b hash object
46
+ # Calculate a Blake2b digest
35
47
  #
36
- # @param [Hash] opts Blake2b configuration
48
+ # @param [String] message Message to be hashed
49
+ # @param [Hash] options Blake2b configuration
37
50
  # @option opts [String] :key for Blake2b keyed mode
38
51
  # @option opts [Integer] :digest_size size of output digest in bytes
39
52
  # @option opts [String] :salt Provide a salt to support randomised hashing.
@@ -43,39 +56,126 @@ module RbNaCl
43
56
  #
44
57
  # @raise [RbNaCl::LengthError] Invalid length specified for one or more options
45
58
  #
46
- # @return [RbNaCl::Hash::Blake2b] A Blake2b hasher object
47
- def initialize(opts = {})
48
- @key = opts.fetch(:key, nil)
59
+ # @return [String] Blake2b digest of the string as raw bytes
60
+ def self.digest(message, options)
61
+ opts = validate_opts(options)
62
+ digest = Util.zeros(opts[:digest_size])
63
+ generichash_blake2b(digest, opts[:digest_size], message, message.bytesize,
64
+ opts[:key], opts[:key_size], opts[:salt], opts[:personal]) ||
65
+ raise(CryptoError, "Hashing failed!")
66
+ digest
67
+ end
49
68
 
50
- if @key
51
- @key_size = @key.bytesize
52
- raise LengthError, "key too short" if @key_size < KEYBYTES_MIN
53
- raise LengthError, "key too long" if @key_size > KEYBYTES_MAX
69
+ # Validate and sanitize values for Blake2b configuration
70
+ #
71
+ # @param [Hash] options Blake2b configuration
72
+ # @option opts [String] :key for Blake2b keyed mode
73
+ # @option opts [Integer] :digest_size size of output digest in bytes
74
+ # @option opts [String] :salt Provide a salt to support randomised hashing.
75
+ # This is mixed into the parameters block to start the hashing.
76
+ # @option opts [Personal] :personal Provide personalisation string to allow pinning a hash for a particular purpose.
77
+ # This is mixed into the parameters block to start the hashing
78
+ #
79
+ # @raise [RbNaCl::LengthError] Invalid length specified for one or more options
80
+ #
81
+ # @return [Hash] opts Configuration hash with sanitized values
82
+ def self.validate_opts(opts)
83
+ key = opts.fetch(:key, nil)
84
+ if key
85
+ key_size = key.bytesize
86
+ raise LengthError, "key too short" if key_size < KEYBYTES_MIN
87
+ raise LengthError, "key too long" if key_size > KEYBYTES_MAX
54
88
  else
55
- @key_size = 0
89
+ key_size = 0
56
90
  end
91
+ opts[:key_size] = key_size
57
92
 
58
- @digest_size = opts.fetch(:digest_size, BYTES_MAX)
59
- raise LengthError, "digest size too short" if @digest_size < BYTES_MIN
60
- raise LengthError, "digest size too long" if @digest_size > BYTES_MAX
93
+ digest_size = opts.fetch(:digest_size, BYTES_MAX)
94
+ raise LengthError, "digest size too short" if digest_size < BYTES_MIN
95
+ raise LengthError, "digest size too long" if digest_size > BYTES_MAX
96
+ opts[:digest_size] = digest_size
61
97
 
62
- @personal = opts.fetch(:personal, EMPTY_PERSONAL)
63
- @personal = Util.zero_pad(PERSONALBYTES, @personal)
98
+ personal = opts.fetch(:personal, EMPTY_PERSONAL)
99
+ opts[:personal] = Util.zero_pad(PERSONALBYTES, personal)
64
100
 
65
- @salt = opts.fetch(:salt, EMPTY_SALT)
66
- @salt = Util.zero_pad(SALTBYTES, @salt)
101
+ salt = opts.fetch(:salt, EMPTY_SALT)
102
+ opts[:salt] = Util.zero_pad(SALTBYTES, salt)
103
+ opts
67
104
  end
68
105
 
69
- # Calculate a Blake2b digest
106
+ private_class_method :validate_opts
107
+
108
+ def self.new(opts = {})
109
+ opts = validate_opts(opts)
110
+ super
111
+ end
112
+
113
+ # Create a new Blake2b hash object
114
+ #
115
+ # @param [Hash] opts Blake2b configuration
116
+ # @option opts [String] :key for Blake2b keyed mode
117
+ # @option opts [Integer] :digest_size size of output digest in bytes
118
+ # @option opts [String] :salt Provide a salt to support randomised hashing.
119
+ # This is mixed into the parameters block to start the hashing.
120
+ # @option opts [Personal] :personal Provide personalisation string to allow pinning a hash for a particular purpose.
121
+ # This is mixed into the parameters block to start the hashing
122
+ #
123
+ # @raise [RbNaCl::LengthError] Invalid length specified for one or more options
124
+ #
125
+ # @return [RbNaCl::Hash::Blake2b] A Blake2b hasher object
126
+ def initialize(opts = {})
127
+ @key = opts[:key]
128
+ @key_size = opts[:key_size]
129
+ @digest_size = opts[:digest_size]
130
+ @personal = opts[:personal]
131
+ @salt = opts[:salt]
132
+
133
+ @incycle = false
134
+ @instate = nil
135
+ end
136
+
137
+ # Initialize state for Blake2b hash calculation,
138
+ # this will be called automatically from #update if needed
139
+ def reset
140
+ @instate.release if @instate
141
+ @instate = State.new
142
+ self.class.generichash_blake2b_init(@instate.pointer, @key, @key_size, @digest_size, @salt, @personal) ||
143
+ raise(CryptoError, "Hash init failed!")
144
+ @incycle = true
145
+ @digest = nil
146
+ end
147
+
148
+ # Reentrant version of Blake2b digest calculation method
70
149
  #
71
150
  # @param [String] message Message to be hashed
151
+ def update(message)
152
+ reset unless @incycle
153
+ self.class.generichash_blake2b_update(@instate.pointer, message, message.bytesize) ||
154
+ raise(CryptoError, "Hashing failed!")
155
+ end
156
+ alias << update
157
+
158
+ # Finalize digest calculation, return cached digest if any
72
159
  #
73
160
  # @return [String] Blake2b digest of the string as raw bytes
74
- def digest(message)
75
- digest = Util.zeros(@digest_size)
76
- self.class.generichash_blake2b(digest, @digest_size, message, message.bytesize, @key, @key_size, @salt, @personal) ||
77
- raise(CryptoError, "Hashing failed!")
78
- digest
161
+ def digest
162
+ raise(CryptoError, "No message to hash yet!") unless @incycle
163
+ return @digest if @digest
164
+ @digest = Util.zeros(@digest_size)
165
+ self.class.generichash_blake2b_final(@instate.pointer, @digest, @digest_size) ||
166
+ raise(CryptoError, "Hash finalization failed!")
167
+ @digest
168
+ end
169
+
170
+ # The crypto_generichash_blake2b_state struct representation
171
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_generichash_blake2b.h#L23
172
+ class State < FFI::Struct
173
+ layout :h, [:uint64, 8],
174
+ :t, [:uint64, 2],
175
+ :f, [:uint64, 2],
176
+ :buf, [:uint8, 2 * 128],
177
+ :buflen, :size_t,
178
+ :last_node, :uint8
79
179
  end
80
180
  end
81
181
  end
@@ -4,5 +4,5 @@
4
4
  # NaCl/libsodium for Ruby
5
5
  module RbNaCl
6
6
  # The library's version
7
- VERSION = "4.0.2"
7
+ VERSION = "5.0.0"
8
8
  end
@@ -14,6 +14,29 @@ RSpec.describe RbNaCl::Hash::Blake2b do
14
14
  expect(RbNaCl::Hash.blake2b("")).to eq empty_string_hash
15
15
  end
16
16
 
17
+ context "arbitrary length message API" do
18
+ let(:blake2b) { RbNaCl::Hash::Blake2b.new }
19
+
20
+ it "calculates the correct hash for a reference string" do
21
+ blake2b << reference_string
22
+ expect(blake2b.digest).to eq reference_string_hash
23
+ end
24
+
25
+ it "calculates the correct hash for an empty string" do
26
+ blake2b << ""
27
+ expect(blake2b.digest).to eq empty_string_hash
28
+ end
29
+
30
+ it "raise CryptoError when digest called without reset / message" do
31
+ expect { blake2b.digest }.to raise_error(RbNaCl::CryptoError)
32
+ end
33
+
34
+ it "calculates hash for empty string when digest called directly after reset" do
35
+ blake2b.reset
36
+ expect(blake2b.digest).to eq empty_string_hash
37
+ end
38
+ end
39
+
17
40
  context "keyed" do
18
41
  let(:reference_string) { vector :blake2b_keyed_message }
19
42
  let(:reference_key) { vector :blake2b_key }
@@ -26,6 +49,23 @@ RSpec.describe RbNaCl::Hash::Blake2b do
26
49
  it "doesn't accept empty strings as a key" do
27
50
  expect { RbNaCl::Hash.blake2b(reference_string, key: "") }.to raise_error(RbNaCl::LengthError)
28
51
  end
52
+
53
+ context "arbitrary length message API" do
54
+ let(:blake2b) { RbNaCl::Hash::Blake2b.new(key: "") }
55
+ let(:blake2b_wk) { RbNaCl::Hash::Blake2b.new(key: reference_key) }
56
+
57
+ it "calculates keyed hashes correctly" do
58
+ blake2b_wk << reference_string
59
+ expect(blake2b_wk.digest).to eq reference_string_hash
60
+ end
61
+
62
+ it "doesn't accept empty strings as a key" do
63
+ expect do
64
+ blake2b << reference_string
65
+ blake2b.digest
66
+ end.to raise_error(RbNaCl::LengthError)
67
+ end
68
+ end
29
69
  end
30
70
 
31
71
  context "personalized" do
@@ -42,6 +82,21 @@ RSpec.describe RbNaCl::Hash::Blake2b do
42
82
  it "calculates personalised hashes correctly with a short personal" do
43
83
  expect(RbNaCl::Hash.blake2b(reference_string, personal: reference_personal_short)).to eq reference_personal_short_hash
44
84
  end
85
+
86
+ context "arbitrary length message API" do
87
+ let(:blake2b) { RbNaCl::Hash::Blake2b.new(personal: reference_personal) }
88
+ let(:blake2b_sh) { RbNaCl::Hash::Blake2b.new(personal: reference_personal_short) }
89
+
90
+ it "calculates personalised hashes correctly" do
91
+ blake2b << reference_string
92
+ expect(blake2b.digest).to eq reference_personal_hash
93
+ end
94
+
95
+ it "calculates personalised hashes correctly with a short personal" do
96
+ blake2b_sh << reference_string
97
+ expect(blake2b_sh.digest).to eq reference_personal_short_hash
98
+ end
99
+ end
45
100
  end
46
101
 
47
102
  context "salted" do
@@ -58,5 +113,20 @@ RSpec.describe RbNaCl::Hash::Blake2b do
58
113
  it "calculates saltised hashes correctly with a short salt" do
59
114
  expect(RbNaCl::Hash.blake2b(reference_string, salt: reference_salt_short)).to eq reference_salt_short_hash
60
115
  end
116
+
117
+ context "arbitrary length message API" do
118
+ let(:blake2b) { RbNaCl::Hash::Blake2b.new(salt: reference_salt) }
119
+ let(:blake2b_sh) { RbNaCl::Hash::Blake2b.new(salt: reference_salt_short) }
120
+
121
+ it "calculates saltised hashes correctly" do
122
+ blake2b << reference_string
123
+ expect(blake2b.digest).to eq reference_salt_hash
124
+ end
125
+
126
+ it "calculates saltised hashes correctly with a short salt" do
127
+ blake2b_sh << reference_string
128
+ expect(blake2b_sh.digest).to eq reference_salt_short_hash
129
+ end
130
+ end
61
131
  end
62
132
  end
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: 4.0.2
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
@@ -9,34 +9,34 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-03-13 00:00:00.000000000 Z
12
+ date: 2017-06-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - '>='
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - '>='
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - '>='
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - '>='
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  description: The Networking and Cryptography (NaCl) library provides a high-level
@@ -48,13 +48,13 @@ executables: []
48
48
  extensions: []
49
49
  extra_rdoc_files: []
50
50
  files:
51
- - ".coveralls.yml"
52
- - ".gitignore"
53
- - ".rspec"
54
- - ".rubocop.yml"
55
- - ".ruby-version"
56
- - ".travis.yml"
57
- - ".yardopts"
51
+ - .coveralls.yml
52
+ - .gitignore
53
+ - .rspec
54
+ - .rubocop.yml
55
+ - .ruby-version
56
+ - .travis.yml
57
+ - .yardopts
58
58
  - CHANGES.md
59
59
  - Gemfile
60
60
  - Guardfile
@@ -139,17 +139,17 @@ require_paths:
139
139
  - lib
140
140
  required_ruby_version: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - ">="
142
+ - - '>='
143
143
  - !ruby/object:Gem::Version
144
144
  version: 2.2.6
145
145
  required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  requirements:
147
- - - ">="
147
+ - - '>='
148
148
  - !ruby/object:Gem::Version
149
149
  version: '0'
150
150
  requirements: []
151
151
  rubyforge_project:
152
- rubygems_version: 2.6.10
152
+ rubygems_version: 2.0.14.1
153
153
  signing_key:
154
154
  specification_version: 4
155
155
  summary: Ruby binding to the Networking and Cryptography (NaCl) library