rbnacl 5.0.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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