rbnacl 1.1.0 → 2.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 (80) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.travis.yml +1 -5
  4. data/CHANGES.md +27 -0
  5. data/Gemfile +4 -1
  6. data/Guardfile +8 -0
  7. data/README.md +52 -3
  8. data/lib/rbnacl/auth.rb +22 -19
  9. data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/private_key.rb +26 -23
  10. data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key.rb +13 -12
  11. data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +185 -0
  12. data/lib/rbnacl/group_elements/curve25519.rb +81 -0
  13. data/lib/rbnacl/hash/blake2b.rb +64 -0
  14. data/lib/rbnacl/hash/sha256.rb +15 -0
  15. data/lib/rbnacl/hash/sha512.rb +15 -0
  16. data/lib/rbnacl/hash.rb +30 -14
  17. data/lib/rbnacl/hmac/sha256.rb +19 -17
  18. data/lib/rbnacl/hmac/sha512256.rb +18 -19
  19. data/lib/rbnacl/init.rb +10 -0
  20. data/lib/rbnacl/{keys/key_comparator.rb → key_comparator.rb} +1 -1
  21. data/lib/rbnacl/{auth/one_time.rb → one_time_auths/poly1305.rb} +21 -19
  22. data/lib/rbnacl/rake_tasks.rb +7 -6
  23. data/lib/rbnacl/random.rb +12 -3
  24. data/lib/rbnacl/random_nonce_box.rb +9 -14
  25. data/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb +125 -0
  26. data/lib/rbnacl/self_test.rb +67 -43
  27. data/lib/rbnacl/serializable.rb +4 -12
  28. data/lib/rbnacl/signatures/ed25519/signing_key.rb +104 -0
  29. data/lib/rbnacl/signatures/ed25519/verify_key.rb +78 -0
  30. data/lib/rbnacl/signatures/ed25519.rb +15 -0
  31. data/lib/rbnacl/sodium/version.rb +23 -0
  32. data/lib/rbnacl/sodium.rb +43 -0
  33. data/lib/rbnacl/test_vectors.rb +34 -1
  34. data/lib/rbnacl/util.rb +50 -7
  35. data/lib/rbnacl/version.rb +2 -2
  36. data/lib/rbnacl.rb +64 -29
  37. data/rbnacl.gemspec +6 -5
  38. data/spec/rbnacl/{auth/one_time_spec.rb → authenticators/poly1305_spec.rb} +2 -2
  39. data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb +65 -0
  40. data/spec/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key_spec.rb +10 -13
  41. data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +39 -0
  42. data/spec/rbnacl/{point_spec.rb → group_element_spec.rb} +6 -8
  43. data/spec/rbnacl/hash/blake2b_spec.rb +30 -0
  44. data/spec/rbnacl/hash_spec.rb +13 -33
  45. data/spec/rbnacl/hmac/sha256_spec.rb +2 -2
  46. data/spec/rbnacl/hmac/sha512256_spec.rb +2 -2
  47. data/spec/rbnacl/random_nonce_box_spec.rb +21 -26
  48. data/spec/rbnacl/random_spec.rb +3 -3
  49. data/spec/rbnacl/secret_box_spec.rb +6 -6
  50. data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +30 -0
  51. data/spec/rbnacl/signatures/ed25519/verify_key_spec.rb +39 -0
  52. data/spec/rbnacl/util_spec.rb +67 -53
  53. data/spec/shared/authenticator.rb +36 -55
  54. data/spec/shared/box.rb +10 -10
  55. data/spec/shared/key_equality.rb +3 -3
  56. data/spec/shared/serializable.rb +17 -0
  57. data/spec/spec_helper.rb +15 -16
  58. data/tasks/rspec.rake +1 -0
  59. data.tar.gz.sig +2 -3
  60. metadata +41 -42
  61. metadata.gz.sig +2 -2
  62. data/lib/rbnacl/box.rb +0 -171
  63. data/lib/rbnacl/encoder.rb +0 -44
  64. data/lib/rbnacl/encoders/base32.rb +0 -33
  65. data/lib/rbnacl/encoders/base64.rb +0 -30
  66. data/lib/rbnacl/encoders/hex.rb +0 -30
  67. data/lib/rbnacl/encoders/raw.rb +0 -12
  68. data/lib/rbnacl/keys/signing_key.rb +0 -95
  69. data/lib/rbnacl/keys/verify_key.rb +0 -96
  70. data/lib/rbnacl/nacl.rb +0 -146
  71. data/lib/rbnacl/point.rb +0 -70
  72. data/lib/rbnacl/secret_box.rb +0 -119
  73. data/spec/rbnacl/box_spec.rb +0 -42
  74. data/spec/rbnacl/encoder_spec.rb +0 -14
  75. data/spec/rbnacl/encoders/base32_spec.rb +0 -16
  76. data/spec/rbnacl/encoders/base64_spec.rb +0 -15
  77. data/spec/rbnacl/encoders/hex_spec.rb +0 -15
  78. data/spec/rbnacl/keys/private_key_spec.rb +0 -68
  79. data/spec/rbnacl/keys/signing_key_spec.rb +0 -39
  80. data/spec/rbnacl/keys/verify_key_spec.rb +0 -51
@@ -0,0 +1,64 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module Hash
4
+ # The Blake2b hash function
5
+ #
6
+ # Blake2b is based on Blake, a SHA3 finalist which was snubbed in favor of
7
+ # Keccak, a much slower hash function but one sufficiently different from
8
+ # SHA2 to let the SHA3 judges panel sleep easy. Back in the real world,
9
+ # it'd be great if we can calculate hashes quickly if possible.
10
+ #
11
+ # Blake2b provides for up to 64-bit digests and also supports a keyed mode
12
+ # similar to HMAC
13
+ class Blake2b
14
+ extend Sodium
15
+
16
+ sodium_type :generichash
17
+ sodium_primitive :blake2b
18
+ sodium_constant :BYTES_MIN
19
+ sodium_constant :BYTES_MAX
20
+ sodium_constant :KEYBYTES_MIN
21
+ sodium_constant :KEYBYTES_MAX
22
+
23
+ sodium_function :generichash_blake2b,
24
+ :crypto_generichash_blake2b,
25
+ [:pointer, :ulong_long, :pointer, :ulong_long, :pointer, :ulong_long]
26
+
27
+ # Create a new Blake2b hash object
28
+ #
29
+ # @param [Hash] opts Blake2b configuration
30
+ # @option opts [String] :key for Blake2b keyed mode
31
+ # @option opts [Integer] :digest_size size of output digest in bytes
32
+ #
33
+ # @raise [RbNaCl::LengthError] Invalid length specified for one or more options
34
+ #
35
+ # @return [RbNaCl::Hash::Blake2b] A Blake2b hasher object
36
+ def initialize(opts = {})
37
+ @key = opts.fetch(:key, nil)
38
+
39
+ if @key
40
+ @key_size = @key.bytesize
41
+ raise LengthError, "key too short" if @key_size < KEYBYTES_MIN
42
+ raise LengthError, "key too long" if @key_size > KEYBYTES_MAX
43
+ else
44
+ @key_size = 0
45
+ end
46
+
47
+ @digest_size = opts.fetch(:digest_size, BYTES_MAX)
48
+ raise LengthError, "digest size too short" if @digest_size < BYTES_MIN
49
+ raise LengthError, "digest size too long" if @digest_size > BYTES_MAX
50
+ end
51
+
52
+ # Calculate a Blake2b digest
53
+ #
54
+ # @param [String] message Message to be hashed
55
+ #
56
+ # @return [String] Blake2b digest of the string as raw bytes
57
+ def digest(message)
58
+ digest = Util.zeros(@digest_size)
59
+ self.class.generichash_blake2b(digest, @digest_size, message, message.bytesize, @key, @key_size) || raise(CryptoError, "Hashing failed!")
60
+ digest
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module Hash
4
+ # Provides a binding for the SHA256 function in libsodium
5
+ module SHA256
6
+ extend Sodium
7
+ sodium_type :hash
8
+ sodium_primitive :sha256
9
+ sodium_constant :BYTES
10
+ sodium_function :hash_sha256,
11
+ :crypto_hash_sha256,
12
+ [:pointer, :pointer, :ulong_long]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module Hash
4
+ # Provides the binding for the SHA512 hash function
5
+ module SHA512
6
+ extend Sodium
7
+ sodium_type :hash
8
+ sodium_primitive :sha512
9
+ sodium_constant :BYTES
10
+ sodium_function :hash_sha512,
11
+ :crypto_hash_sha512,
12
+ [:pointer, :pointer, :ulong_long]
13
+ end
14
+ end
15
+ end
data/lib/rbnacl/hash.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
3
  # Cryptographic hash functions
4
4
  #
5
5
  # Cryptographic hash functions take a variable length message and compute a
@@ -11,38 +11,54 @@ module Crypto
11
11
  # there is no secret involved in the hashing, so anyone can create the hash of
12
12
  # a given message.
13
13
  #
14
- # RbNaCl provides the SHA-256 and SHA-512 hash functions.
14
+ # RbNaCl provides the SHA-256,SHA-512 as well as the Blake2b hash functions.
15
15
  module Hash
16
16
  # Returns the SHA-256 hash of the given data
17
17
  #
18
18
  # There's no streaming done, just pass in the data and be done with it.
19
19
  #
20
- # @param [String] data The data, as a collection of bytes
21
- # @param [#to_sym] encoding Encoding of the returned hash.
20
+ # @param [#to_str] data The data, as a collection of bytes
22
21
  #
23
22
  # @raise [CryptoError] If the hashing fails for some reason.
24
23
  #
25
24
  # @return [String] The SHA-256 hash as raw bytes (Or encoded as per the second argument)
26
- def self.sha256(data, encoding = :raw)
27
- hash = Util.zeros(NaCl::SHA256BYTES)
28
- NaCl.crypto_hash_sha256(hash, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
29
- Encoder[encoding].encode(hash)
25
+ def self.sha256(data)
26
+ data = data.to_str
27
+ digest = Util.zeros(SHA256::BYTES)
28
+ SHA256.hash_sha256(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
29
+ digest
30
30
  end
31
31
 
32
32
  # Returns the SHA-512 hash of the given data
33
33
  #
34
34
  # There's no streaming done, just pass in the data and be done with it.
35
35
  #
36
- # @param [String] data The data, as a collection of bytes
37
- # @param [#to_sym] encoding Encoding of the returned hash.
36
+ # @param [#to_str] data The data, as a collection of bytes
38
37
  #
39
38
  # @raise [CryptoError] If the hashing fails for some reason.
40
39
  #
41
40
  # @return [String] The SHA-512 hash as raw bytes (Or encoded as per the second argument)
42
- def self.sha512(data, encoding = :raw)
43
- hash = Util.zeros(NaCl::SHA512BYTES)
44
- NaCl.crypto_hash_sha512(hash, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
45
- Encoder[encoding].encode(hash)
41
+ def self.sha512(data)
42
+ digest = Util.zeros(SHA512::BYTES)
43
+ SHA512.hash_sha512(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
44
+ digest
45
+ end
46
+
47
+ # Returns the Blake2b hash of the given data
48
+ #
49
+ # There's no streaming done, just pass in the data and be done with it.
50
+ # This method returns a 64-byte hash by default.
51
+ #
52
+ # @param [String] data The data, as a collection of bytes
53
+ # @option options [Fixnum] digest_size Size in bytes (1-64, default 64)
54
+ # @option options [String] key 64-byte (or less) key for keyed mode
55
+ #
56
+ # @raise [CryptoError] If the hashing fails for some reason.
57
+ #
58
+ # @return [String] The blake2b hash as raw bytes (Or encoded as per the second argument)
59
+ def self.blake2b(data, options = {})
60
+ key = options[:key]
61
+ Blake2b.new(options).digest(data)
46
62
  end
47
63
  end
48
64
  end
@@ -1,9 +1,9 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
3
  module HMAC
4
4
  # Computes an authenticator as HMAC-SHA-256
5
5
  #
6
- # The authenticator can be used at a later time to verify the provenence of
6
+ # The authenticator can be used at a later time to verify the provenance of
7
7
  # the message by recomputing the HMAC over the message and then comparing it to
8
8
  # the provided authenticator. The class provides methods for generating
9
9
  # signatures and also has a constant-time implementation for checking them.
@@ -13,26 +13,28 @@ module Crypto
13
13
  #
14
14
  # @see http://nacl.cr.yp.to/auth.html
15
15
  class SHA256 < Auth
16
- # Number of bytes in a valid key
17
- KEYBYTES = NaCl::HMACSHA256_KEYBYTES
16
+ extend Sodium
18
17
 
19
- # Number of bytes in a valid authenticator
20
- BYTES = NaCl::HMACSHA256_BYTES
21
-
22
- # The crypto primitive for the HMAC::SHA256 class
23
- #
24
- # @return [Symbol] The primitive used
25
- def self.primitive
26
- :hmac_sha256
27
- end
18
+ sodium_type :auth
19
+ sodium_primitive :hmacsha256
20
+ sodium_constant :BYTES
21
+ sodium_constant :KEYBYTES
28
22
 
23
+ sodium_function :auth_hmacsha256,
24
+ :crypto_auth_hmacsha256,
25
+ [:pointer, :pointer, :ulong_long, :pointer]
26
+
27
+ sodium_function :auth_hmacsha256_verify,
28
+ :crypto_auth_hmacsha256_verify,
29
+ [:pointer, :pointer, :ulong_long, :pointer]
30
+
29
31
  private
30
- def compute_authenticator(message, authenticator)
31
- NaCl.crypto_auth_hmacsha256(authenticator, message, message.bytesize, key)
32
+ def compute_authenticator(authenticator, message)
33
+ self.class.auth_hmacsha256(authenticator, message, message.bytesize, key)
32
34
  end
33
35
 
34
- def verify_message(message, authenticator)
35
- NaCl.crypto_auth_hmacsha256_verify(authenticator, message, message.bytesize, key)
36
+ def verify_message(authenticator, message)
37
+ self.class.auth_hmacsha256_verify(authenticator, message, message.bytesize, key)
36
38
  end
37
39
  end
38
40
  end
@@ -1,9 +1,9 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
3
  module HMAC
4
4
  # Computes an authenticator as HMAC-SHA-512 truncated to 256-bits
5
5
  #
6
- # The authenticator can be used at a later time to verify the provenence of
6
+ # The authenticator can be used at a later time to verify the provenance of
7
7
  # the message by recomputing the HMAC over the message and then comparing it to
8
8
  # the provided authenticator. The class provides methods for generating
9
9
  # signatures and also has a constant-time implementation for checking them.
@@ -13,30 +13,29 @@ module Crypto
13
13
  #
14
14
  # @see http://nacl.cr.yp.to/auth.html
15
15
  class SHA512256 < Auth
16
- # Number of bytes in a valid key
17
- KEYBYTES = NaCl::HMACSHA512256_KEYBYTES
16
+ extend Sodium
18
17
 
19
- # Number of bytes in a valid authenticator
20
- BYTES = NaCl::HMACSHA512256_BYTES
18
+ sodium_type :auth
19
+ sodium_primitive :hmacsha512256
20
+ sodium_constant :BYTES
21
+ sodium_constant :KEYBYTES
22
+
23
+ sodium_function :auth_hmacsha512256,
24
+ :crypto_auth_hmacsha512256,
25
+ [:pointer, :pointer, :ulong_long, :pointer]
21
26
 
22
- # The crypto primitive for the HMAC::SHA512256 class
23
- #
24
- # @return [Symbol] The primitive used
25
- def self.primitive
26
- :hmac_sha512256
27
- end
27
+ sodium_function :auth_hmacsha512256_verify,
28
+ :crypto_auth_hmacsha512256_verify,
29
+ [:pointer, :pointer, :ulong_long, :pointer]
28
30
 
29
31
  private
30
- def compute_authenticator(message, authenticator)
31
- NaCl.crypto_auth_hmacsha512256(authenticator, message, message.bytesize, key)
32
+ def compute_authenticator(authenticator, message)
33
+ self.class.auth_hmacsha512256(authenticator, message, message.bytesize, key)
32
34
  end
33
35
 
34
- def verify_message(message, authenticator)
35
- NaCl.crypto_auth_hmacsha512256_verify(authenticator, message, message.bytesize, key)
36
+ def verify_message(authenticator, message)
37
+ self.class.auth_hmacsha512256_verify(authenticator, message, message.bytesize, key)
36
38
  end
37
39
  end
38
-
39
- # TIMTOWTDI!
40
- SHA512 = SHA512256
41
40
  end
42
41
  end
@@ -0,0 +1,10 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ # Defines the libsodium init function
4
+ module Init
5
+ extend FFI::Library
6
+ ffi_lib 'sodium'
7
+
8
+ attach_function :sodium_init, [], :int
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
3
  # Implements comparisons of keys
4
4
  #
5
5
  # This permits both timing invariant equality tests, as well as
@@ -1,9 +1,9 @@
1
1
  # encoding: binary
2
- module Crypto
3
- class Auth
2
+ module RbNaCl
3
+ module OneTimeAuths
4
4
  # Computes an authenticator using poly1305
5
5
  #
6
- # The authenticator can be used at a later time to verify the provenence of
6
+ # The authenticator can be used at a later time to verify the provenance of
7
7
  # the message by recomputing the tag over the message and then comparing it to
8
8
  # the provided authenticator. The class provides methods for generating
9
9
  # signatures and also has a constant-time implementation for checking them.
@@ -17,27 +17,29 @@ module Crypto
17
17
  # can also create them.
18
18
  #
19
19
  # @see http://nacl.cr.yp.to/onetimeauth.html
20
- class OneTime < self
21
- # Number of bytes in a valid key
22
- KEYBYTES = NaCl::ONETIME_KEYBYTES
20
+ class Poly1305 < Auth
21
+ extend Sodium
23
22
 
24
- # Number of bytes in a valid authenticator
25
- BYTES = NaCl::ONETIME_BYTES
26
-
27
- # The crypto primitive for the Auth::OneTime class
28
- #
29
- # @return [Symbol] The primitive used
30
- def self.primitive
31
- :poly_1305
32
- end
23
+ sodium_type :onetimeauth
24
+ sodium_primitive :poly1305
25
+ sodium_constant :BYTES
26
+ sodium_constant :KEYBYTES
27
+
28
+ sodium_function :onetimeauth_poly1305,
29
+ :crypto_onetimeauth_poly1305,
30
+ [:pointer, :pointer, :ulong_long, :pointer]
31
+
32
+ sodium_function :onetimeauth_poly1305_verify,
33
+ :crypto_onetimeauth_poly1305_verify,
34
+ [:pointer, :pointer, :ulong_long, :pointer]
33
35
 
34
36
  private
35
- def compute_authenticator(message, authenticator)
36
- NaCl.crypto_auth_onetime(authenticator, message, message.bytesize, key)
37
+ def compute_authenticator(authenticator, message)
38
+ self.class.onetimeauth_poly1305(authenticator, message, message.bytesize, key)
37
39
  end
38
40
 
39
- def verify_message(message, authenticator)
40
- NaCl.crypto_auth_onetime_verify(authenticator, message, message.bytesize, key)
41
+ def verify_message(authenticator, message)
42
+ self.class.onetimeauth_poly1305_verify(authenticator, message, message.bytesize, key)
41
43
  end
42
44
 
43
45
  end
@@ -3,7 +3,8 @@ require 'rake'
3
3
  require 'rake/clean'
4
4
  require 'digest/sha2'
5
5
 
6
- LIBSODIUM_VERSION = "0.2"
6
+ LIBSODIUM_VERSION = "0.4.5"
7
+ LIBSODIUM_DIGEST = "7ad5202df53eeac0eb29b064ae5d05b65d82b2fc1c082899c9c6a09b0ee1ac32"
7
8
 
8
9
  def sh_hidden(command)
9
10
  STDERR.puts("*** Executing: #{command}")
@@ -19,17 +20,17 @@ end
19
20
  libsodium_tarball = "libsodium-#{LIBSODIUM_VERSION}.tar.gz"
20
21
 
21
22
  file libsodium_tarball do
22
- sh "curl -O http://download.dnscrypt.org/libsodium/releases/libsodium-#{LIBSODIUM_VERSION}.tar.gz"
23
+ sh "curl -L -O https://github.com/jedisct1/libsodium/releases/download/#{LIBSODIUM_VERSION}/#{libsodium_tarball}"
23
24
 
24
25
  digest = Digest::SHA256.hexdigest(File.read(libsodium_tarball))
25
- if digest != "e99a6b69adc080a5acf6b8a49fdc74b61d6f3579b590e85c93446a8325dde100"
26
+ if digest != LIBSODIUM_DIGEST
26
27
  rm libsodium_tarball
27
- raise "#{libsodium_tarball} failed checksum!"
28
+ raise "#{libsodium_tarball} failed checksum! Got #{digest}"
28
29
  end
29
30
  end
30
31
 
31
- file "libsodium" => "libsodium-#{LIBSODIUM_VERSION}.tar.gz" do
32
- sh "tar xzf libsodium-#{LIBSODIUM_VERSION}.tar.gz"
32
+ file "libsodium" => libsodium_tarball do
33
+ sh "tar -zxf #{libsodium_tarball}"
33
34
  mv "libsodium-#{LIBSODIUM_VERSION}", "libsodium"
34
35
  end
35
36
 
data/lib/rbnacl/random.rb CHANGED
@@ -1,18 +1,27 @@
1
+ require 'thread'
2
+
1
3
  # encoding: binary
2
- module Crypto
4
+ module RbNaCl
3
5
  # Functions for random number generation
4
6
  #
5
7
  # This uses the underlying source of random number generation on the OS, so
6
8
  # /dev/urandom on UNIX-like systems, and the MS crypto providor on windows.
7
9
  module Random
10
+ extend Sodium
11
+
12
+ @mutex = Mutex.new
13
+
14
+ sodium_function :c_random_bytes,
15
+ :randombytes_buf,
16
+ [:pointer, :ulong_long]
8
17
  # Returns a string of random bytes
9
18
  #
10
19
  # @param [Integer] n number of random bytes desired
11
20
  #
12
21
  # @return [String] random bytes.
13
22
  def self.random_bytes(n=32)
14
- buf = Crypto::Util.zeros(n)
15
- NaCl.random_bytes(buf, n)
23
+ buf = RbNaCl::Util.zeros(n)
24
+ @mutex.synchronize { c_random_bytes(buf, n) }
16
25
  buf
17
26
  end
18
27
  end
@@ -1,15 +1,15 @@
1
1
  # encoding: binary
2
2
  require 'forwardable'
3
- module Crypto
3
+ module RbNaCl
4
4
  # The simplest nonce strategy that could possibly work
5
5
  #
6
6
  # This class implements the simplest possible nonce generation strategy to
7
- # wrap a Crypto::Box or Crypto::SecretBox. A 24-byte random nonce is used
7
+ # wrap a RbNaCl::Box or RbNaCl::SecretBox. A 24-byte random nonce is used
8
8
  # for the encryption and is prepended to the message. When it is time to
9
9
  # open the box, the message is split into nonce and ciphertext, and then the
10
10
  # box is decrypted.
11
11
  #
12
- # Thanks to the size of the nonce, the chance of a collision is neglible. For
12
+ # Thanks to the size of the nonce, the chance of a collision is negligible. For
13
13
  # example, after encrypting 2^64 messages, the odds of their having been
14
14
  # repeated nonce is approximately 2^-64. As an additional convenience, the
15
15
  # ciphertexts may be encoded or decoded by any of the encoders implemented in
@@ -31,10 +31,6 @@ module Crypto
31
31
  extend Forwardable
32
32
  def_delegators :@box, :nonce_bytes, :primitive
33
33
 
34
- # the size of the nonce
35
- # DO NOT USE THIS, use the #nonce_bytes method instead
36
- NONCEBYTES = NaCl::NONCEBYTES
37
-
38
34
  # Create a new RandomNonceBox
39
35
  #
40
36
  # @param box [SecretBox, Box] the SecretBox or Box to use.
@@ -75,14 +71,14 @@ module Crypto
75
71
  # the nonce prepended. Optionally encodes the message using an encoder.
76
72
  #
77
73
  # @param message [String] The message to encrypt
78
- # @param encoding [Symbol] Optional encoding for the returned ciphertext
79
74
  #
80
75
  # @return [String] The enciphered message
81
- def box(message, encoding = :raw)
76
+ def box(message)
82
77
  nonce = generate_nonce
83
78
  cipher_text = @box.box(nonce, message)
84
- Encoder[encoding].encode(nonce + cipher_text)
79
+ nonce + cipher_text
85
80
  end
81
+ alias encrypt box
86
82
 
87
83
  # Decrypts the ciphertext with a random nonce
88
84
  #
@@ -90,16 +86,15 @@ module Crypto
90
86
  # front and uses this to decrypt. Returns the message.
91
87
  #
92
88
  # @param enciphered_message [String] The message to decrypt.
93
- # @param encoding [Symbol] Optional decoding for the returned ciphertext
94
89
  #
95
90
  # @raise [CryptoError] If the message has been tampered with.
96
91
  #
97
92
  # @return [String] The decoded message
98
- def open(enciphered_message, encoding = :raw)
99
- decoded = Encoder[encoding].decode(enciphered_message)
100
- nonce, ciphertext = *extract_nonce(decoded)
93
+ def open(enciphered_message)
94
+ nonce, ciphertext = extract_nonce(enciphered_message.to_s)
101
95
  @box.open(nonce, ciphertext)
102
96
  end
97
+ alias decrypt open
103
98
 
104
99
  private
105
100
  def generate_nonce
@@ -0,0 +1,125 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module SecretBoxes
4
+ # The SecretBox class boxes and unboxes messages
5
+ #
6
+ # This class uses the given secret key to encrypt and decrypt messages.
7
+ #
8
+ # It is VITALLY important that the nonce is a nonce, i.e. it is a number used
9
+ # only once for any given pair of keys. If you fail to do this, you
10
+ # compromise the privacy of the messages encrypted. Give your nonces a
11
+ # different prefix, or have one side use an odd counter and one an even counter.
12
+ # Just make sure they are different.
13
+ #
14
+ # The ciphertexts generated by this class include a 16-byte authenticator which
15
+ # is checked as part of the decryption. An invalid authenticator will cause
16
+ # the unbox function to raise. The authenticator is not a signature. Once
17
+ # you've looked in the box, you've demonstrated the ability to create
18
+ # arbitrary valid messages, so messages you send are repudiable. For
19
+ # non-repudiable messages, sign them before or after encryption.
20
+ class XSalsa20Poly1305
21
+ extend Sodium
22
+
23
+ sodium_type :secretbox
24
+ sodium_primitive :xsalsa20poly1305
25
+ sodium_constant :KEYBYTES
26
+ sodium_constant :NONCEBYTES
27
+ sodium_constant :ZEROBYTES
28
+ sodium_constant :BOXZEROBYTES
29
+
30
+ sodium_function :secretbox_xsalsa20poly1305,
31
+ :crypto_secretbox_xsalsa20poly1305,
32
+ [:pointer, :pointer, :ulong_long, :pointer, :pointer]
33
+
34
+ sodium_function :secretbox_xsalsa20poly1305_open,
35
+ :crypto_secretbox_xsalsa20poly1305_open,
36
+ [:pointer, :pointer, :ulong_long, :pointer, :pointer]
37
+
38
+ # Create a new SecretBox
39
+ #
40
+ # Sets up the Box with a secret key fro encrypting and decrypting messages.
41
+ #
42
+ # @param key [String] The key to encrypt and decrypt with
43
+ #
44
+ # @raise [RbNaCl::LengthError] on invalid keys
45
+ #
46
+ # @return [RbNaCl::SecretBox] The new Box, ready to use
47
+ def initialize(key)
48
+ @key = Util.check_string(key, KEYBYTES, "Secret key")
49
+ end
50
+
51
+ # Encrypts a message
52
+ #
53
+ # Encrypts the message with the given nonce to the key set up when
54
+ # initializing the class. Make sure the nonce is unique for any given
55
+ # key, or you might as well just send plain text.
56
+ #
57
+ # This function takes care of the padding required by the NaCL C API.
58
+ #
59
+ # @param nonce [String] A 24-byte string containing the nonce.
60
+ # @param message [String] The message to be encrypted.
61
+ #
62
+ # @raise [RbNaCl::LengthError] If the nonce is not valid
63
+ #
64
+ # @return [String] The ciphertext without the nonce prepended (BINARY encoded)
65
+ def box(nonce, message)
66
+ Util.check_length(nonce, nonce_bytes, "Nonce")
67
+ msg = Util.prepend_zeros(ZEROBYTES, message)
68
+ ct = Util.zeros(msg.bytesize)
69
+
70
+ self.class.secretbox_xsalsa20poly1305(ct, msg, msg.bytesize, nonce, @key) || raise(CryptoError, "Encryption failed")
71
+ Util.remove_zeros(BOXZEROBYTES, ct)
72
+ end
73
+ alias encrypt box
74
+
75
+ # Decrypts a ciphertext
76
+ #
77
+ # Decrypts the ciphertext with the given nonce using the key setup when
78
+ # initializing the class.
79
+ #
80
+ # This function takes care of the padding required by the NaCL C API.
81
+ #
82
+ # @param nonce [String] A 24-byte string containing the nonce.
83
+ # @param ciphertext [String] The message to be decrypted.
84
+ #
85
+ # @raise [RbNaCl::LengthError] If the nonce is not valid
86
+ # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated.
87
+ #
88
+ # @return [String] The decrypted message (BINARY encoded)
89
+ def open(nonce, ciphertext)
90
+ Util.check_length(nonce, nonce_bytes, "Nonce")
91
+ ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext)
92
+ message = Util.zeros(ct.bytesize)
93
+
94
+ self.class.secretbox_xsalsa20poly1305_open(message, ct, ct.bytesize, nonce, @key) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
95
+ Util.remove_zeros(ZEROBYTES, message)
96
+ end
97
+ alias decrypt open
98
+
99
+ # The crypto primitive for the SecretBox instance
100
+ #
101
+ # @return [Symbol] The primitive used
102
+ def primitive; self.class.primitive; end
103
+
104
+ # The nonce bytes for the SecretBox class
105
+ #
106
+ # @return [Integer] The number of bytes in a valid nonce
107
+ def self.nonce_bytes; NONCEBYTES; end
108
+
109
+ # The nonce bytes for the SecretBox instance
110
+ #
111
+ # @return [Integer] The number of bytes in a valid nonce
112
+ def nonce_bytes; NONCEBYTES; end
113
+
114
+ # The key bytes for the SecretBox class
115
+ #
116
+ # @return [Integer] The number of bytes in a valid key
117
+ def self.key_bytes; KEYBYTES; end
118
+
119
+ # The key bytes for the SecretBox instance
120
+ #
121
+ # @return [Integer] The number of bytes in a valid key
122
+ def key_bytes; KEYBYTES; end
123
+ end
124
+ end
125
+ end