rbnacl 5.0.0 → 6.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.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +34 -12
  4. data/.travis.yml +16 -16
  5. data/CHANGES.md +37 -10
  6. data/Gemfile +4 -3
  7. data/Guardfile +2 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +31 -21
  10. data/Rakefile +4 -3
  11. data/lib/rbnacl.rb +8 -3
  12. data/lib/rbnacl/aead/base.rb +3 -0
  13. data/lib/rbnacl/aead/chacha20poly1305_ietf.rb +2 -2
  14. data/lib/rbnacl/aead/chacha20poly1305_legacy.rb +2 -2
  15. data/lib/rbnacl/aead/xchacha20poly1305_ietf.rb +44 -0
  16. data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +6 -5
  17. data/lib/rbnacl/boxes/curve25519xsalsa20poly1305/private_key.rb +1 -1
  18. data/lib/rbnacl/group_elements/curve25519.rb +2 -1
  19. data/lib/rbnacl/hash/blake2b.rb +6 -4
  20. data/lib/rbnacl/hash/sha256.rb +1 -1
  21. data/lib/rbnacl/hash/sha512.rb +1 -1
  22. data/lib/rbnacl/hmac/sha256.rb +73 -8
  23. data/lib/rbnacl/hmac/sha512.rb +73 -8
  24. data/lib/rbnacl/hmac/sha512256.rb +71 -8
  25. data/lib/rbnacl/init.rb +1 -5
  26. data/lib/rbnacl/one_time_auths/poly1305.rb +2 -2
  27. data/lib/rbnacl/password_hash.rb +33 -2
  28. data/lib/rbnacl/password_hash/argon2.rb +37 -18
  29. data/lib/rbnacl/password_hash/scrypt.rb +1 -1
  30. data/lib/rbnacl/random.rb +1 -3
  31. data/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb +2 -2
  32. data/lib/rbnacl/signatures/ed25519/signing_key.rb +2 -2
  33. data/lib/rbnacl/signatures/ed25519/verify_key.rb +1 -1
  34. data/lib/rbnacl/sodium.rb +16 -12
  35. data/lib/rbnacl/sodium/version.rb +3 -1
  36. data/lib/rbnacl/test_vectors.rb +104 -44
  37. data/lib/rbnacl/util.rb +92 -8
  38. data/lib/rbnacl/version.rb +1 -1
  39. data/rbnacl.gemspec +6 -7
  40. data/spec/rbnacl/aead/xchacha20poly1305_ietf_spec.rb +14 -0
  41. data/spec/rbnacl/authenticators/poly1305_spec.rb +21 -1
  42. data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +18 -6
  43. data/spec/rbnacl/hmac/sha256_spec.rb +6 -1
  44. data/spec/rbnacl/hmac/sha512256_spec.rb +6 -1
  45. data/spec/rbnacl/hmac/sha512_spec.rb +6 -1
  46. data/spec/rbnacl/password_hash/argon2_spec.rb +56 -14
  47. data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +5 -4
  48. data/spec/rbnacl/util_spec.rb +63 -4
  49. data/spec/shared/aead.rb +33 -13
  50. data/spec/shared/authenticator.rb +0 -19
  51. data/spec/shared/box.rb +18 -6
  52. data/spec/shared/hmac.rb +46 -0
  53. data/spec/spec_helper.rb +3 -1
  54. metadata +22 -18
  55. data/.ruby-version +0 -1
@@ -16,11 +16,11 @@ module RbNaCl
16
16
 
17
17
  sodium_function :aead_chacha20poly1305_encrypt,
18
18
  :crypto_aead_chacha20poly1305_encrypt,
19
- [:pointer, :pointer, :pointer, :ulong_long, :pointer, :ulong_long, :pointer, :pointer, :pointer]
19
+ %i[pointer pointer pointer ulong_long pointer ulong_long pointer pointer pointer]
20
20
 
21
21
  sodium_function :aead_chacha20poly1305_decrypt,
22
22
  :crypto_aead_chacha20poly1305_decrypt,
23
- [:pointer, :pointer, :pointer, :pointer, :ulong_long, :pointer, :ulong_long, :pointer, :pointer]
23
+ %i[pointer pointer pointer pointer ulong_long pointer ulong_long pointer pointer]
24
24
 
25
25
  private
26
26
 
@@ -0,0 +1,44 @@
1
+ # encoding: binary
2
+ # frozen_string_literal: true
3
+
4
+ module RbNaCl
5
+ module AEAD
6
+ # This class contains wrappers for the IETF implementation of
7
+ # Authenticated Encryption with Additional Data using ChaCha20-Poly1305
8
+ class XChaCha20Poly1305IETF < RbNaCl::AEAD::Base
9
+ extend Sodium
10
+ if Sodium::Version.supported_version?("1.0.12")
11
+ sodium_type :aead
12
+ sodium_primitive :xchacha20poly1305_ietf
13
+
14
+ sodium_constant :KEYBYTES
15
+ sodium_constant :NPUBBYTES
16
+ sodium_constant :ABYTES
17
+
18
+ sodium_function :aead_xchacha20poly1305_ietf_encrypt,
19
+ :crypto_aead_xchacha20poly1305_ietf_encrypt,
20
+ %i[pointer pointer pointer ulong_long pointer ulong_long pointer pointer pointer]
21
+
22
+ sodium_function :aead_xchacha20poly1305_ietf_decrypt,
23
+ :crypto_aead_xchacha20poly1305_ietf_decrypt,
24
+ %i[pointer pointer pointer pointer ulong_long pointer ulong_long pointer pointer]
25
+
26
+ private
27
+
28
+ def do_encrypt(ciphertext, ciphertext_len, nonce, message, additional_data)
29
+ self.class.aead_xchacha20poly1305_ietf_encrypt(ciphertext, ciphertext_len,
30
+ message, data_len(message),
31
+ additional_data, data_len(additional_data),
32
+ nil, nonce, @key)
33
+ end
34
+
35
+ def do_decrypt(message, message_len, nonce, ciphertext, additional_data)
36
+ self.class.aead_xchacha20poly1305_ietf_decrypt(message, message_len, nil,
37
+ ciphertext, data_len(ciphertext),
38
+ additional_data, data_len(additional_data),
39
+ nonce, @key)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -18,7 +18,7 @@ module RbNaCl
18
18
  # #=> #<RbNaCl::PrivateKey ...>
19
19
  #
20
20
  # # send bobkey.public_key to alice
21
- # # recieve alice's public key, alicepk
21
+ # # receive alice's public key, alicepk
22
22
  # # NB: This is actually the hard part of the system. How to do it securely
23
23
  # # is left as an exercise to for the reader.
24
24
  # alice_pubkey = "..."
@@ -77,15 +77,15 @@ module RbNaCl
77
77
 
78
78
  sodium_function :box_curve25519xsalsa20poly1305_beforenm,
79
79
  :crypto_box_curve25519xsalsa20poly1305_beforenm,
80
- [:pointer, :pointer, :pointer]
80
+ %i[pointer pointer pointer]
81
81
 
82
82
  sodium_function :box_curve25519xsalsa20poly1305_open_afternm,
83
83
  :crypto_box_curve25519xsalsa20poly1305_open_afternm,
84
- [:pointer, :pointer, :ulong_long, :pointer, :pointer]
84
+ %i[pointer pointer ulong_long pointer pointer]
85
85
 
86
86
  sodium_function :box_curve25519xsalsa20poly1305_afternm,
87
87
  :crypto_box_curve25519xsalsa20poly1305_afternm,
88
- [:pointer, :pointer, :ulong_long, :pointer, :pointer]
88
+ %i[pointer pointer ulong_long pointer pointer]
89
89
 
90
90
  # Create a new Box
91
91
  #
@@ -180,10 +180,11 @@ module RbNaCl
180
180
  private
181
181
 
182
182
  def beforenm
183
- @_key ||= begin
183
+ @beforenm ||= begin
184
184
  key = Util.zeros(BEFORENMBYTES)
185
185
  success = self.class.box_curve25519xsalsa20poly1305_beforenm(key, @public_key.to_s, @private_key.to_s)
186
186
  raise CryptoError, "Failed to derive shared key" unless success
187
+
187
188
  key
188
189
  end
189
190
  end
@@ -24,7 +24,7 @@ module RbNaCl
24
24
 
25
25
  sodium_function :box_curve25519xsalsa20poly1305_keypair,
26
26
  :crypto_box_curve25519xsalsa20poly1305_keypair,
27
- [:pointer, :pointer]
27
+ %i[pointer pointer]
28
28
 
29
29
  # The size of the key, in bytes
30
30
  BYTES = Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES
@@ -31,7 +31,7 @@ module RbNaCl
31
31
 
32
32
  sodium_function :scalarmult_curve25519,
33
33
  :crypto_scalarmult_curve25519,
34
- [:pointer, :pointer, :pointer]
34
+ %i[pointer pointer pointer]
35
35
 
36
36
  # Number of bytes in a scalar on this curve
37
37
  SCALARBYTES = 32
@@ -68,6 +68,7 @@ module RbNaCl
68
68
  result = Util.zeros(SCALARBYTES)
69
69
 
70
70
  raise CryptoError, "degenerate key detected" unless self.class.scalarmult_curve25519(result, integer, @point)
71
+
71
72
  self.class.new(result)
72
73
  end
73
74
 
@@ -26,19 +26,19 @@ module RbNaCl
26
26
 
27
27
  sodium_function :generichash_blake2b,
28
28
  :crypto_generichash_blake2b_salt_personal,
29
- [:pointer, :size_t, :pointer, :ulong_long, :pointer, :size_t, :pointer, :pointer]
29
+ %i[pointer size_t pointer ulong_long pointer size_t pointer pointer]
30
30
 
31
31
  sodium_function :generichash_blake2b_init,
32
32
  :crypto_generichash_blake2b_init_salt_personal,
33
- [:pointer, :pointer, :size_t, :size_t, :pointer, :pointer]
33
+ %i[pointer pointer size_t size_t pointer pointer]
34
34
 
35
35
  sodium_function :generichash_blake2b_update,
36
36
  :crypto_generichash_blake2b_update,
37
- [:pointer, :pointer, :ulong_long]
37
+ %i[pointer pointer ulong_long]
38
38
 
39
39
  sodium_function :generichash_blake2b_final,
40
40
  :crypto_generichash_blake2b_final,
41
- [:pointer, :pointer, :size_t]
41
+ %i[pointer pointer size_t]
42
42
 
43
43
  EMPTY_PERSONAL = ("\0" * PERSONALBYTES).freeze
44
44
  EMPTY_SALT = ("\0" * SALTBYTES).freeze
@@ -93,6 +93,7 @@ module RbNaCl
93
93
  digest_size = opts.fetch(:digest_size, BYTES_MAX)
94
94
  raise LengthError, "digest size too short" if digest_size < BYTES_MIN
95
95
  raise LengthError, "digest size too long" if digest_size > BYTES_MAX
96
+
96
97
  opts[:digest_size] = digest_size
97
98
 
98
99
  personal = opts.fetch(:personal, EMPTY_PERSONAL)
@@ -161,6 +162,7 @@ module RbNaCl
161
162
  def digest
162
163
  raise(CryptoError, "No message to hash yet!") unless @incycle
163
164
  return @digest if @digest
165
+
164
166
  @digest = Util.zeros(@digest_size)
165
167
  self.class.generichash_blake2b_final(@instate.pointer, @digest, @digest_size) ||
166
168
  raise(CryptoError, "Hash finalization failed!")
@@ -11,7 +11,7 @@ module RbNaCl
11
11
  sodium_constant :BYTES
12
12
  sodium_function :hash_sha256,
13
13
  :crypto_hash_sha256,
14
- [:pointer, :pointer, :ulong_long]
14
+ %i[pointer pointer ulong_long]
15
15
  end
16
16
  end
17
17
  end
@@ -11,7 +11,7 @@ module RbNaCl
11
11
  sodium_constant :BYTES
12
12
  sodium_function :hash_sha512,
13
13
  :crypto_hash_sha512,
14
- [:pointer, :pointer, :ulong_long]
14
+ %i[pointer pointer ulong_long]
15
15
  end
16
16
  end
17
17
  end
@@ -22,23 +22,88 @@ module RbNaCl
22
22
  sodium_constant :BYTES
23
23
  sodium_constant :KEYBYTES
24
24
 
25
- sodium_function :auth_hmacsha256,
26
- :crypto_auth_hmacsha256,
27
- [:pointer, :pointer, :ulong_long, :pointer]
25
+ sodium_function :auth_hmacsha256_init,
26
+ :crypto_auth_hmacsha256_init,
27
+ %i[pointer pointer size_t]
28
28
 
29
- sodium_function :auth_hmacsha256_verify,
30
- :crypto_auth_hmacsha256_verify,
31
- [:pointer, :pointer, :ulong_long, :pointer]
29
+ sodium_function :auth_hmacsha256_update,
30
+ :crypto_auth_hmacsha256_update,
31
+ %i[pointer pointer ulong_long]
32
+
33
+ sodium_function :auth_hmacsha256_final,
34
+ :crypto_auth_hmacsha256_final,
35
+ %i[pointer pointer]
36
+
37
+ # Create instance without checking key length
38
+ #
39
+ # RFC 2104 HMAC
40
+ # The key for HMAC can be of any length.
41
+ #
42
+ # see https://tools.ietf.org/html/rfc2104#section-3
43
+ def initialize(key)
44
+ @key = Util.check_hmac_key(key, "#{self.class} key")
45
+ @state = State.new
46
+ @authenticator = Util.zeros(tag_bytes)
47
+
48
+ self.class.auth_hmacsha256_init(@state, key, key.bytesize)
49
+ end
50
+
51
+ # Compute authenticator for message
52
+ #
53
+ # @params [#to_str] message message to construct an authenticator for
54
+ def update(message)
55
+ self.class.auth_hmacsha256_update(@state, message, message.bytesize)
56
+ self.class.auth_hmacsha256_final(@state.clone, @authenticator)
57
+
58
+ hexdigest
59
+ end
60
+
61
+ # Return the authenticator, as raw bytes
62
+ #
63
+ # @return [String] The authenticator, as raw bytes
64
+ def digest
65
+ @authenticator
66
+ end
67
+
68
+ # Return the authenticator, as hex string
69
+ #
70
+ # @return [String] The authenticator, as hex string
71
+ def hexdigest
72
+ @authenticator.unpack("H*").last
73
+ end
32
74
 
33
75
  private
34
76
 
35
77
  def compute_authenticator(authenticator, message)
36
- self.class.auth_hmacsha256(authenticator, message, message.bytesize, key)
78
+ state = State.new
79
+
80
+ self.class.auth_hmacsha256_init(state, key, key.bytesize)
81
+ self.class.auth_hmacsha256_update(state, message, message.bytesize)
82
+ self.class.auth_hmacsha256_final(state, authenticator)
37
83
  end
38
84
 
85
+ # libsodium crypto_auth_hmacsha256_verify works only for 32 byte keys
86
+ # ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha256/auth_hmacsha256.c#L109
39
87
  def verify_message(authenticator, message)
40
- self.class.auth_hmacsha256_verify(authenticator, message, message.bytesize, key)
88
+ correct = Util.zeros(BYTES)
89
+ compute_authenticator(correct, message)
90
+ Util.verify32(correct, authenticator)
41
91
  end
42
92
  end
93
+
94
+ # The crypto_auth_hmacsha256_state struct representation
95
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha256.h
96
+ class SHA256State < FFI::Struct
97
+ layout :state, [:uint32, 8],
98
+ :count, :uint64,
99
+ :buf, [:uint8, 64]
100
+ end
101
+
102
+ # The crypto_hash_sha256_state struct representation
103
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha256.h
104
+ class State < FFI::Struct
105
+ layout :ictx, SHA256State,
106
+ :octx, SHA256State
107
+ end
43
108
  end
44
109
  end
@@ -22,23 +22,88 @@ module RbNaCl
22
22
  sodium_constant :BYTES
23
23
  sodium_constant :KEYBYTES
24
24
 
25
- sodium_function :auth_hmacsha512,
26
- :crypto_auth_hmacsha512,
27
- [:pointer, :pointer, :ulong_long, :pointer]
25
+ sodium_function :auth_hmacsha512_init,
26
+ :crypto_auth_hmacsha512_init,
27
+ %i[pointer pointer size_t]
28
28
 
29
- sodium_function :auth_hmacsha512_verify,
30
- :crypto_auth_hmacsha512_verify,
31
- [:pointer, :pointer, :ulong_long, :pointer]
29
+ sodium_function :auth_hmacsha512_update,
30
+ :crypto_auth_hmacsha512_update,
31
+ %i[pointer pointer ulong_long]
32
+
33
+ sodium_function :auth_hmacsha512_final,
34
+ :crypto_auth_hmacsha512_final,
35
+ %i[pointer pointer]
36
+
37
+ # Create instance without checking key length
38
+ #
39
+ # RFC 2104 HMAC
40
+ # The key for HMAC can be of any length.
41
+ #
42
+ # see https://tools.ietf.org/html/rfc2104#section-3
43
+ def initialize(key)
44
+ @key = Util.check_hmac_key(key, "#{self.class} key")
45
+ @state = State.new
46
+ @authenticator = Util.zeros(tag_bytes)
47
+
48
+ self.class.auth_hmacsha512_init(@state, key, key.bytesize)
49
+ end
50
+
51
+ # Compute authenticator for message
52
+ #
53
+ # @params [#to_str] message message to construct an authenticator for
54
+ def update(message)
55
+ self.class.auth_hmacsha512_update(@state, message, message.bytesize)
56
+ self.class.auth_hmacsha512_final(@state.clone, @authenticator)
57
+
58
+ hexdigest
59
+ end
60
+
61
+ # Return the authenticator, as raw bytes
62
+ #
63
+ # @return [String] The authenticator, as raw bytes
64
+ def digest
65
+ @authenticator
66
+ end
67
+
68
+ # Return the authenticator, as hex string
69
+ #
70
+ # @return [String] The authenticator, as hex string
71
+ def hexdigest
72
+ @authenticator.unpack("H*").last
73
+ end
32
74
 
33
75
  private
34
76
 
35
77
  def compute_authenticator(authenticator, message)
36
- self.class.auth_hmacsha512(authenticator, message, message.bytesize, key)
78
+ state = State.new
79
+
80
+ self.class.auth_hmacsha512_init(state, key, key.bytesize)
81
+ self.class.auth_hmacsha512_update(state, message, message.bytesize)
82
+ self.class.auth_hmacsha512_final(state, authenticator)
37
83
  end
38
84
 
85
+ # libsodium crypto_auth_hmacsha512_verify works only for 32 byte keys
86
+ # ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha512/auth_hmacsha512.c#L109
39
87
  def verify_message(authenticator, message)
40
- self.class.auth_hmacsha512_verify(authenticator, message, message.bytesize, key)
88
+ correct = Util.zeros(BYTES)
89
+ compute_authenticator(correct, message)
90
+ Util.verify64(correct, authenticator)
41
91
  end
42
92
  end
93
+
94
+ # The crypto_auth_hmacsha512_state struct representation
95
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512.h
96
+ class SHA512State < FFI::Struct
97
+ layout :state, [:uint64, 8],
98
+ :count, [:uint64, 2],
99
+ :buf, [:uint8, 128]
100
+ end
101
+
102
+ # The crypto_hash_sha512_state struct representation
103
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h
104
+ class State < FFI::Struct
105
+ layout :ictx, SHA512State,
106
+ :octx, SHA512State
107
+ end
43
108
  end
44
109
  end
@@ -22,23 +22,86 @@ module RbNaCl
22
22
  sodium_constant :BYTES
23
23
  sodium_constant :KEYBYTES
24
24
 
25
- sodium_function :auth_hmacsha512256,
26
- :crypto_auth_hmacsha512256,
27
- [:pointer, :pointer, :ulong_long, :pointer]
25
+ sodium_function :auth_hmacsha512256_init,
26
+ :crypto_auth_hmacsha512256_init,
27
+ %i[pointer pointer size_t]
28
28
 
29
- sodium_function :auth_hmacsha512256_verify,
30
- :crypto_auth_hmacsha512256_verify,
31
- [:pointer, :pointer, :ulong_long, :pointer]
29
+ sodium_function :auth_hmacsha512256_update,
30
+ :crypto_auth_hmacsha512256_update,
31
+ %i[pointer pointer ulong_long]
32
+
33
+ sodium_function :auth_hmacsha512256_final,
34
+ :crypto_auth_hmacsha512256_final,
35
+ %i[pointer pointer]
36
+
37
+ # Create instance without checking key length
38
+ #
39
+ # RFC 2104 HMAC
40
+ # The key for HMAC can be of any length.
41
+ #
42
+ # see https://tools.ietf.org/html/rfc2104#section-3
43
+ def initialize(key)
44
+ @key = Util.check_hmac_key(key, "#{self.class} key")
45
+ @state = State.new
46
+ @authenticator = Util.zeros(tag_bytes)
47
+
48
+ self.class.auth_hmacsha512256_init(@state, key, key.bytesize)
49
+ end
50
+
51
+ # Compute authenticator for message
52
+ #
53
+ # @params [#to_str] message message to construct an authenticator for
54
+ def update(message)
55
+ self.class.auth_hmacsha512256_update(@state, message, message.bytesize)
56
+ self.class.auth_hmacsha512256_final(@state.clone, @authenticator)
57
+
58
+ hexdigest
59
+ end
60
+
61
+ # Return the authenticator, as raw bytes
62
+ #
63
+ # @return [String] The authenticator, as raw bytes
64
+ def digest
65
+ @authenticator
66
+ end
67
+
68
+ # Return the authenticator, as hex string
69
+ #
70
+ # @return [String] The authenticator, as hex string
71
+ def hexdigest
72
+ @authenticator.unpack("H*").last
73
+ end
32
74
 
33
75
  private
34
76
 
35
77
  def compute_authenticator(authenticator, message)
36
- self.class.auth_hmacsha512256(authenticator, message, message.bytesize, key)
78
+ state = State.new
79
+
80
+ self.class.auth_hmacsha512256_init(state, key, key.bytesize)
81
+ self.class.auth_hmacsha512256_update(state, message, message.bytesize)
82
+ self.class.auth_hmacsha512256_final(state, authenticator)
37
83
  end
38
84
 
39
85
  def verify_message(authenticator, message)
40
- self.class.auth_hmacsha512256_verify(authenticator, message, message.bytesize, key)
86
+ correct = Util.zeros(BYTES)
87
+ compute_authenticator(correct, message)
88
+ Util.verify32(correct, authenticator)
41
89
  end
42
90
  end
91
+
92
+ # The crypto_auth_hmacsha512256_state struct representation
93
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512256.h
94
+ class SHA512256State < FFI::Struct
95
+ layout :state, [:uint64, 8],
96
+ :count, [:uint64, 2],
97
+ :buf, [:uint8, 128]
98
+ end
99
+
100
+ # The crypto_hash_sha512_state struct representation
101
+ # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h
102
+ class State < FFI::Struct
103
+ layout :ictx, SHA512256State,
104
+ :octx, SHA512256State
105
+ end
43
106
  end
44
107
  end