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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f8462f580b5f1517e510c7cf5137b4dc5edec1f
4
- data.tar.gz: e6ef35925227eeb5e49edb8868ab1f375002fa3a
3
+ metadata.gz: 4868c75138fed2d13cc2c2e101961e5149a2f950
4
+ data.tar.gz: 9b2bc9e35ff45cf67715ae49a86f3667dff2609a
5
5
  SHA512:
6
- metadata.gz: 3f66ffdf3087fd9f5b77f85c0e87f68825ed7c9c4cfe07c45d37cab48f299971cd4e07e0a443dde9fa7d7bf245df0834eda82cc4a9f1c4afc52c10cc0602b184
7
- data.tar.gz: a25f2a0fbed4b8b09a9c8bbb4e2d4029e0327684483b1aabf7f2ac8d7023cab716b51a78a38c5531c786f9a143ad6b8c5176a6aafa27ca6347a34f4379aaf06c
6
+ metadata.gz: 6667126547e0562e40b3d653b998058a4cc2f4dab18063d636285ca957d5b3c500eac93966946bcf9989bcad24c312208edbb856b34d53391d6ce7d2eec97932
7
+ data.tar.gz: 4e2d2f6ac34fa25972361afa81e8d0ae1c08f6b344e3fba43cdba92790daf1b00c824b564f4c5a3a64070fb2b7a6f9698e546ede8ec9088295a43355528958cd
checksums.yaml.gz.sig CHANGED
Binary file
data/.travis.yml CHANGED
@@ -1,15 +1,11 @@
1
1
  script: "LD_LIBRARY_PATH=lib bundle exec rake ci"
2
2
 
3
3
  rvm:
4
- - 1.8.7
5
4
  - 1.9.3
6
5
  - 2.0.0
7
- - ree
8
6
  - ruby-head
9
- - jruby-18mode
10
- - jruby-19mode
7
+ - jruby
11
8
  - jruby-head
12
- - rbx-18mode
13
9
  - rbx-19mode
14
10
 
15
11
  matrix:
data/CHANGES.md CHANGED
@@ -1,3 +1,30 @@
1
+ 2.0.0 (2013-11-07)
2
+ ------------------
3
+ * Add encrypt/decrypt aliases for Crypto::RandomNonceBox
4
+ * Rename Crypto module to RbNaCl module
5
+ * RbNaCl::VerifyKey#verify operand order was reversed. New operand order is
6
+ signature, message instead of message, signature
7
+ * RbNaCL::SecretBox#open, RbNaCl::Box#open, Auth#verify and VerifyKey#verify
8
+ all now raise a (descendent of) CryptoError if the check fails. This ensures
9
+ failures are handled by the program.
10
+ * RbNaCl::SecretBox, Box, etc. are all now aliases for the real implementations,
11
+ which are named after the primitives they provide
12
+ * Encoders have now gone.
13
+ * Add support for the Blake2b cryptographic hash algorithm.
14
+ * Add checks that we have a sufficiently recent version of libsodium (0.4.3+)
15
+ * Dropped ruby-1.8 support
16
+ * Call the `sodium_init()` function, to select the best algorithms.
17
+ * Fix some typos in the documentation
18
+ * Changes in the low level binding for libsodium and removal of the NaCl module
19
+ * Add a mutex around calls to randombytes in libsodium
20
+
21
+ 1.1.0 (2013-04-19)
22
+ ------------------
23
+
24
+ * Provide API for querying primitives and details about them, such as key
25
+ lengths, nonce lengths, etc.
26
+ * Fixed bug on passing null bytes to sha256, sha512 functions.
27
+
1
28
  1.0.0 (2013-03-08)
2
29
  ------------------
3
30
  * Initial release
data/Gemfile CHANGED
@@ -3,7 +3,10 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in rbnacl.gemspec
4
4
  gemspec
5
5
 
6
+ group :development do
7
+ gem 'guard-rspec'
8
+ end
9
+
6
10
  group :test do
7
- gem 'base32'
8
11
  gem 'coveralls', :require => false
9
12
  end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md CHANGED
@@ -2,7 +2,6 @@
2
2
  ======
3
3
  [![Gem Version](https://badge.fury.io/rb/rbnacl.png)](http://badge.fury.io/rb/rbnacl)
4
4
  [![Build Status](https://travis-ci.org/cryptosphere/rbnacl.png?branch=master)](https://travis-ci.org/cryptosphere/rbnacl)
5
- [![Dependency Status](https://gemnasium.com/cryptosphere/rbnacl.png)](https://gemnasium.com/cryptosphere/rbnacl)
6
5
  [![Code Climate](https://codeclimate.com/github/cryptosphere/rbnacl.png)](https://codeclimate.com/github/cryptosphere/rbnacl)
7
6
  [![Coverage Status](https://coveralls.io/repos/cryptosphere/rbnacl/badge.png?branch=master)](https://coveralls.io/r/cryptosphere/rbnacl)
8
7
 
@@ -47,6 +46,10 @@ is extremely fast with comparatively small cryptographic keys.
47
46
  For more information on NaCl's goals, see Dan Bernstein's presentation
48
47
  [Blaming the Cryptographic User](http://cr.yp.to/talks/2012.08.08/slides.pdf)
49
48
 
49
+ ### Is it any good?
50
+
51
+ [Yes.](http://news.ycombinator.com/item?id=3067434)
52
+
50
53
  ## Supported platforms
51
54
 
52
55
  You can use RbNaCl anywhere you can get libsodium installed (see below).
@@ -54,7 +57,6 @@ RbNaCl is continuously integration tested on the following Ruby VMs:
54
57
 
55
58
  * MRI 2.0
56
59
  * MRI 1.9 (YARV)
57
- * MRI 1.8 / REE
58
60
  * JRuby 1.7 (in both 1.8/1.9 mode)
59
61
  * Rubinius HEAD (in both 1.8/1.9 mode)
60
62
 
@@ -200,6 +202,53 @@ Coursera offers from Stanford University Professor Dan Boneh:
200
202
 
201
203
  [http://crypto-class.org](http://crypto-class.org)
202
204
 
205
+ ## Important Questions
206
+
207
+ ### Is it "Military Grade™"?
208
+
209
+ Only if your military understands twisted Edwards curves
210
+
211
+ ### Does it have a lock with a checkmark?
212
+
213
+ Sure, here you go:
214
+
215
+ ![Checkmarked Lock](http://i.imgur.com/dwA0Ffi.png)
216
+
217
+ ### Is it full of NSA backdoors?
218
+
219
+ ![No NIST](http://i.imgur.com/HSxeAmp.png)
220
+
221
+ The design of RbNaCl's primitives is completely free from NIST (and by
222
+ association, NSA) influence, with the following minor exceptions:
223
+
224
+ * The Poly1305 MAC, used for authenticating integrity of ciphertexts, uses AES
225
+ as a replaceable component
226
+ * The Ed25519 digital signature algorithm uses SHA-512 for both key derivation
227
+ and computing message digests
228
+ * APIs are provided to certain NIST hash functions, including SHA-256, SHA-512,
229
+ and their associated HMAC counterparts
230
+
231
+ Otherwise, all of the algorithms in NaCl were designed by Dan Bernstein and his
232
+ collaborators.
233
+
234
+ The design choices in NaCl, particularly in regard to the Curve25519
235
+ Diffie-Hellman function, emphasize security (whereas [NIST curves emphasize
236
+ "performance" at the cost of security][nist-security-dangers]), and "magic
237
+ constants" in NaCl are picked by theorems designed to maximize security.
238
+ The same cannot be said of NIST curves, where the specific origins of certain
239
+ constants are not described by the standards and may be subject to malicious
240
+ influence by the NSA.
241
+
242
+ It is the opinion of this library's authors that Dan Bernstein is unlikely to be
243
+ subject to NSA influence (although we have no way of actually knowing this).
244
+
245
+ Dan Bernstein's designs have been well-scrutinized both as part of the [ESTREAM
246
+ Project](https://en.wikipedia.org/wiki/ESTREAM) and the cryptographic community
247
+ as a whole. And despite the emphasis on higher security, NaCl's primitives are
248
+ faster across-the-board than most implementations of the NIST standards.
249
+
250
+ [nist-security-dangers]: http://www.hyperelliptic.org/tanja/vortraege/20130531.pdf
251
+
203
252
  ## Contributing
204
253
 
205
254
  * Fork this repository on Github
@@ -208,5 +257,5 @@ Coursera offers from Stanford University Professor Dan Boneh:
208
257
 
209
258
  ## License
210
259
 
211
- Copyright (c) 2013 Tony Arcieri, Jonathan Stott.
260
+ Copyright (c) 2013 Jonathan Stott, Tony Arcieri.
212
261
  Distributed under the MIT License. See LICENSE.txt for further details.
data/lib/rbnacl/auth.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
+
3
4
  # Secret Key Authenticators
4
5
  #
5
6
  # These provide a means of verifying the integrity of a message, but only
@@ -18,10 +19,8 @@ module Crypto
18
19
  # A new authenticator, ready for auth and verification
19
20
  #
20
21
  # @param [#to_str] key the key used for authenticators, 32 bytes.
21
- # @param [#to_sym] encoding decode key from this format (default raw)
22
- def initialize(key, encoding = :raw)
23
- @key = Encoder[encoding].decode(key)
24
- Util.check_length(@key, key_bytes, "#{self.class} key")
22
+ def initialize(key)
23
+ @key = Util.check_string(key, key_bytes, "#{self.class} key")
25
24
  end
26
25
 
27
26
  # Compute authenticator for message
@@ -37,38 +36,42 @@ module Crypto
37
36
  # Verifies the given authenticator with the message.
38
37
  #
39
38
  # @param [#to_str] key the key used for the authenticator
40
- # @param [#to_str] message the message to be authenticated
41
39
  # @param [#to_str] authenticator to be checked
40
+ # @param [#to_str] message the message to be authenticated
41
+ #
42
+ # @raise [BadAuthenticatorError] if the tag isn't valid
43
+ # @raise [LengthError] if the tag is of the wrong length
42
44
  #
43
45
  # @return [Boolean] Was it valid?
44
- def self.verify(key, message, authenticator)
45
- new(key).verify(message, authenticator)
46
+ def self.verify(key, authenticator, message)
47
+ new(key).verify(authenticator, message)
46
48
  end
47
49
 
48
50
  # Compute authenticator for message
49
51
  #
50
52
  # @param [#to_str] message the message to authenticate
51
- # @param [#to_sym] authenticator_encoding format of the authenticator (default raw)
52
53
  #
53
54
  # @return [String] The authenticator in the requested encoding (default raw)
54
- def auth(message, authenticator_encoding = :raw)
55
+ def auth(message)
55
56
  authenticator = Util.zeros(tag_bytes)
56
57
  message = message.to_str
57
- compute_authenticator(message, authenticator)
58
- Encoder[authenticator_encoding].encode(authenticator)
58
+ compute_authenticator(authenticator, message)
59
+ authenticator
59
60
  end
60
61
 
61
62
  # Verifies the given authenticator with the message.
62
63
  #
63
64
  # @param [#to_str] authenticator to be checked
64
65
  # @param [#to_str] message the message to be authenticated
65
- # @param [#to_sym] authenticator_encoding format of the authenticator (default raw)
66
+ #
67
+ # @raise [BadAuthenticatorError] if the tag isn't valid
68
+ # @raise [LengthError] if the tag is of the wrong length
66
69
  #
67
70
  # @return [Boolean] Was it valid?
68
- def verify(message, authenticator, authenticator_encoding = :raw)
69
- auth = Encoder[authenticator_encoding].decode(authenticator)
70
- return false unless auth.bytesize == tag_bytes
71
- verify_message(message, auth)
71
+ def verify(authenticator, message)
72
+ auth = authenticator.to_s
73
+ Util.check_length(auth, tag_bytes, "Provided authenticator")
74
+ verify_message(auth, message) || raise(BadAuthenticatorError, "Invalid authenticator provided, message is corrupt")
72
75
  end
73
76
 
74
77
  # The crypto primitive for this authenticator instance
@@ -99,7 +102,7 @@ module Crypto
99
102
  def tag_bytes; self.class.tag_bytes; end
100
103
 
101
104
  private
102
- def compute_authenticator(message, authenticator); raise NotImplementedError; end
103
- def verify_message(message, authenticator); raise NotImplementedError; end
105
+ def compute_authenticator(authenticator, message); raise NotImplementedError; end
106
+ def verify_message(authenticator, message); raise NotImplementedError; end
104
107
  end
105
108
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: binary
2
- module Crypto
3
- # Crypto::Box private key. Keep it safe
2
+
3
+ module RbNaCl
4
+ # RbNaCl::Box private key. Keep it safe
4
5
  #
5
6
  # This class generates and stores NaCL private keys, as well as providing a
6
7
  # reference to the public key associated with this private key, if that's
@@ -9,12 +10,22 @@ module Crypto
9
10
  # Note that the documentation for NaCl refers to this as a secret key, but in
10
11
  # this library its a private key, to avoid confusing the issue with the
11
12
  # SecretBox, which does symmetric encryption.
12
- class PrivateKey
13
+ class Boxes::Curve25519XSalsa20Poly1305::PrivateKey
14
+
13
15
  include KeyComparator
14
16
  include Serializable
17
+
18
+ extend Sodium
19
+
20
+ sodium_type :box
21
+ sodium_primitive :curve25519xsalsa20poly1305
22
+
23
+ sodium_function :box_curve25519xsalsa20poly1305_keypair,
24
+ :crypto_box_curve25519xsalsa20poly1305_keypair,
25
+ [:pointer, :pointer]
15
26
 
16
27
  # The size of the key, in bytes
17
- BYTES = NaCl::CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES
28
+ BYTES = Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES
18
29
 
19
30
  # Initializes a new PrivateKey for key operations.
20
31
  #
@@ -25,23 +36,23 @@ module Crypto
25
36
  # @param private_key [String] The private key
26
37
  # @param key_encoding [Symbol] The encoding of the key
27
38
  #
28
- # @raise [Crypto::LengthError] If the key is not valid after decoding.
39
+ # @raise [TypeError] If the key is nil
40
+ # @raise [RbNaCl::LengthError] If the key is not valid after decoding.
29
41
  #
30
42
  # @return A new PrivateKey
31
- def initialize(private_key, key_encoding = :raw)
32
- @private_key = Crypto::Encoder[key_encoding].decode(private_key)
33
- Util.check_length(@private_key, BYTES, "Private key")
43
+ def initialize(private_key)
44
+ @private_key = Util.check_string(private_key, BYTES, "Private key")
34
45
  end
35
46
 
36
47
  # Generates a new keypair
37
48
  #
38
- # @raise [Crypto::CryptoError] if key generation fails, due to insufficient randomness.
49
+ # @raise [RbNaCl::CryptoError] if key generation fails, due to insufficient randomness.
39
50
  #
40
- # @return [Crypto::PrivateKey] A new private key, with the associated public key also set.
51
+ # @return [RbNaCl::PrivateKey] A new private key, with the associated public key also set.
41
52
  def self.generate
42
- pk = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES)
43
- sk = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES)
44
- NaCl.crypto_box_curve25519xsalsa20poly1305_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair")
53
+ pk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PUBLICKEYBYTES)
54
+ sk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES)
55
+ self.box_curve25519xsalsa20poly1305_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair")
45
56
  new(sk)
46
57
  end
47
58
 
@@ -56,22 +67,14 @@ module Crypto
56
67
  #
57
68
  # @return [PublicKey] the key
58
69
  def public_key
59
- @public_key ||= PublicKey.new(Point.base.mult(to_bytes))
60
- end
61
-
62
- # The crypto primitive the PrivateKey class is to be used for
63
- #
64
- # @return [Symbol] The primitive
65
- def self.primitive
66
- :curve25519_xsalsa20_poly1305
70
+ @public_key ||= PublicKey.new GroupElements::Curve25519.base.mult(to_bytes)
67
71
  end
68
-
72
+
69
73
  # The crypto primitive this PrivateKey is to be used for.
70
74
  #
71
75
  # @return [Symbol] The primitive
72
76
  def primitive
73
77
  self.class.primitive
74
78
  end
75
-
76
79
  end
77
80
  end
@@ -1,31 +1,31 @@
1
1
  # encoding: binary
2
- module Crypto
3
- # Crypto::Box public key. Send to your friends.
2
+
3
+ module RbNaCl
4
+ # RbNaCl::Box public key. Send it (securely!) to your friends.
4
5
  #
5
- # This class stores the NaCL public key, and provides some convience
6
+ # This class stores the NaCL public key, and provides some convenience
6
7
  # functions for working with it.
7
- class PublicKey
8
+ class Boxes::Curve25519XSalsa20Poly1305::PublicKey
9
+
8
10
  include KeyComparator
9
11
  include Serializable
10
12
 
11
13
  # The size of the key, in bytes
12
- BYTES = NaCl::CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES
14
+ BYTES = Boxes::Curve25519XSalsa20Poly1305::PUBLICKEYBYTES
13
15
 
14
16
  # Initializes a new PublicKey for key operations.
15
17
  #
16
18
  # Takes the (optionally encoded) public key bytes. This can be shared with
17
19
  # many people and used to establish key pairs with their private key, for
18
- # the exchanging of messages using a Crypto::Box
20
+ # the exchanging of messages using a RbNaCl::Box
19
21
  #
20
22
  # @param public_key [String] The public key
21
- # @param key_encoding [Symbol] The encoding of the key
22
23
  #
23
- # @raise [Crypto::LengthError] If the key is not valid after decoding.
24
+ # @raise [RbNaCl::LengthError] If the key is not valid after decoding.
24
25
  #
25
26
  # @return A new PublicKey
26
- def initialize(public_key, key_encoding = :raw)
27
- @public_key = Crypto::Encoder[key_encoding].decode(public_key)
28
- Util.check_length(@public_key, BYTES, "Public key")
27
+ def initialize(public_key)
28
+ @public_key = Util.check_string(public_key, BYTES, "Public key")
29
29
  end
30
30
 
31
31
  # The raw bytes of the key
@@ -39,7 +39,7 @@ module Crypto
39
39
  #
40
40
  # @return [Symbol] The primitive
41
41
  def self.primitive
42
- :curve25519_xsalsa20_poly1305
42
+ :curve25519xsalsa20poly1305
43
43
  end
44
44
 
45
45
  # The crypto primitive this PublicKey is to be used for.
@@ -49,4 +49,5 @@ module Crypto
49
49
  self.class.primitive
50
50
  end
51
51
  end
52
+
52
53
  end
@@ -0,0 +1,185 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module Boxes
4
+ # The Box class boxes and unboxes messages between a pair of keys
5
+ #
6
+ # This class uses the given public and secret keys to derive a shared key,
7
+ # which is used with the nonce given to encrypt the given messages and
8
+ # decrypt the given ciphertexts. The same shared key will generated from
9
+ # both pairing of keys, so given two keypairs belonging to alice (pkalice,
10
+ # skalice) and bob(pkbob, skbob), the key derived from (pkalice, skbob) with
11
+ # equal that from (pkbob, skalice). This is how the system works:
12
+ #
13
+ # @example
14
+ # # On bob's system
15
+ # bobkey = RbNaCl::PrivateKey.generate
16
+ # #=> #<RbNaCl::PrivateKey ...>
17
+ #
18
+ # # send bobkey.public_key to alice
19
+ # # recieve alice's public key, alicepk
20
+ # # NB: This is actually the hard part of the system. How to do it securely
21
+ # # is left as an exercise to for the reader.
22
+ # alice_pubkey = "..."
23
+ #
24
+ # # make a box
25
+ # alicebob_box = RbNaCl::Box.new(alice_pubkey, bobkey)
26
+ # #=> #<RbNaCl::Box ...>
27
+ #
28
+ # # encrypt a message to alice
29
+ # cipher_text = alicebob_box.box("A bad example of a nonce", "Hello, Alice!")
30
+ # #=> "..." # a string of bytes, 29 bytes long
31
+ #
32
+ # # send ["A bad example of a nonce", cipher_text] to alice
33
+ # # note that nonces don't have to be secret
34
+ # # receive [nonce, cipher_text_to_bob] from alice
35
+ #
36
+ # # decrypt the reply
37
+ # # Alice has been a little more sensible than bob, and has a random nonce
38
+ # # that is too fiddly to type here. But there are other choices than just
39
+ # # random
40
+ # plain_text = alicebob_box.open(nonce, cipher_text_to_bob)
41
+ # #=> "Hey there, Bob!"
42
+ #
43
+ # # we have a new message!
44
+ # # But Eve has tampered with this message, by flipping some bytes around!
45
+ # # [nonce2, cipher_text_to_bob_honest_love_eve]
46
+ # alicebob_box.open(nonce2, cipher_text_to_bob_honest_love_eve)
47
+ #
48
+ # # BOOM!
49
+ # # Bob gets a RbNaCl::CryptoError to deal with!
50
+ #
51
+ # It is VITALLY important that the nonce is a nonce, i.e. it is a number used
52
+ # only once for any given pair of keys. If you fail to do this, you
53
+ # compromise the privacy of the the messages encrypted. Also, bear in mind
54
+ # the property mentioned just above. Give your nonces a different prefix, or
55
+ # have one side use an odd counter and one an even counter. Just make sure
56
+ # they are different.
57
+ #
58
+ # The ciphertexts generated by this class include a 16-byte authenticator which
59
+ # is checked as part of the decryption. An invalid authenticator will cause
60
+ # the unbox function to raise. The authenticator is not a signature. Once
61
+ # you've looked in the box, you've demonstrated the ability to create
62
+ # arbitrary valid messages, so messages you send are repudiable. For
63
+ # non-repudiable messages, sign them before or after encryption.
64
+ class Curve25519XSalsa20Poly1305
65
+ extend Sodium
66
+
67
+ sodium_type :box
68
+ sodium_primitive :curve25519xsalsa20poly1305
69
+ sodium_constant :NONCEBYTES
70
+ sodium_constant :ZEROBYTES
71
+ sodium_constant :BOXZEROBYTES
72
+ sodium_constant :BEFORENMBYTES
73
+ sodium_constant :PUBLICKEYBYTES
74
+ sodium_constant :SECRETKEYBYTES, :PRIVATEKEYBYTES
75
+
76
+ sodium_function :box_curve25519xsalsa20poly1305_beforenm,
77
+ :crypto_box_curve25519xsalsa20poly1305_beforenm,
78
+ [:pointer, :pointer, :pointer]
79
+
80
+ sodium_function :box_curve25519xsalsa20poly1305_open_afternm,
81
+ :crypto_box_curve25519xsalsa20poly1305_open_afternm,
82
+ [:pointer, :pointer, :ulong_long, :pointer, :pointer]
83
+
84
+ sodium_function :box_curve25519xsalsa20poly1305_afternm,
85
+ :crypto_box_curve25519xsalsa20poly1305_afternm,
86
+ [:pointer, :pointer, :ulong_long, :pointer, :pointer]
87
+
88
+ # Create a new Box
89
+ #
90
+ # Sets up the Box for deriving the shared key and encrypting and
91
+ # decrypting messages.
92
+ #
93
+ # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to
94
+ # @param private_key [String,RbNaCl::PrivateKey] The private key to encrypt with
95
+ # @param encoding [Symbol] Parse keys from the given encoding
96
+ #
97
+ # @raise [RbNaCl::LengthError] on invalid keys
98
+ #
99
+ # @return [RbNaCl::Box] The new Box, ready to use
100
+ def initialize(public_key, private_key, encoding = :raw)
101
+ @public_key = PublicKey === public_key ? public_key : PublicKey.new(public_key)
102
+ @private_key = PrivateKey === private_key ? private_key : PrivateKey.new(private_key)
103
+ raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
104
+ end
105
+
106
+ # Encrypts a message
107
+ #
108
+ # Encrypts the message with the given nonce to the keypair set up when
109
+ # initializing the class. Make sure the nonce is unique for any given
110
+ # keypair, or you might as well just send plain text.
111
+ #
112
+ # This function takes care of the padding required by the NaCL C API.
113
+ #
114
+ # @param nonce [String] A 24-byte string containing the nonce.
115
+ # @param message [String] The message to be encrypted.
116
+ #
117
+ # @raise [RbNaCl::LengthError] If the nonce is not valid
118
+ #
119
+ # @return [String] The ciphertext without the nonce prepended (BINARY encoded)
120
+ def box(nonce, message)
121
+ Util.check_length(nonce, nonce_bytes, "Nonce")
122
+ msg = Util.prepend_zeros(ZEROBYTES, message)
123
+ ct = Util.zeros(msg.bytesize)
124
+
125
+ self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
126
+ Util.remove_zeros(BOXZEROBYTES, ct)
127
+ end
128
+ alias encrypt box
129
+
130
+ # Decrypts a ciphertext
131
+ #
132
+ # Decrypts the ciphertext with the given nonce using the keypair setup when
133
+ # initializing the class.
134
+ #
135
+ # This function takes care of the padding required by the NaCL C API.
136
+ #
137
+ # @param nonce [String] A 24-byte string containing the nonce.
138
+ # @param ciphertext [String] The message to be decrypted.
139
+ #
140
+ # @raise [RbNaCl::LengthError] If the nonce is not valid
141
+ # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated.
142
+ #
143
+ # @return [String] The decrypted message (BINARY encoded)
144
+ def open(nonce, ciphertext)
145
+ Util.check_length(nonce, nonce_bytes, "Nonce")
146
+ ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext)
147
+ message = Util.zeros(ct.bytesize)
148
+
149
+ self.class.box_curve25519xsalsa20poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
150
+ Util.remove_zeros(ZEROBYTES, message)
151
+ end
152
+ alias decrypt open
153
+
154
+ # The crypto primitive for the box class
155
+ #
156
+ # @return [Symbol] The primitive used
157
+ def primitive
158
+ self.class.primitive
159
+ end
160
+
161
+ # The nonce bytes for the box class
162
+ #
163
+ # @return [Integer] The number of bytes in a valid nonce
164
+ def self.nonce_bytes
165
+ NONCEBYTES
166
+ end
167
+
168
+ # The nonce bytes for the box instance
169
+ #
170
+ # @return [Integer] The number of bytes in a valid nonce
171
+ def nonce_bytes
172
+ NONCEBYTES
173
+ end
174
+
175
+ private
176
+ def beforenm
177
+ @k ||= begin
178
+ k = Util.zeros(BEFORENMBYTES)
179
+ self.class.box_curve25519xsalsa20poly1305_beforenm(k, @public_key.to_s, @private_key.to_s) || raise(CryptoError, "Failed to derive shared key")
180
+ k
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: binary
2
+ module RbNaCl
3
+ module GroupElements
4
+ # Points provide the interface to NaCl's Curve25519 high-speed elliptic
5
+ # curve cryptography, which can be used for implementing Diffie-Hellman
6
+ # and other forms of public key cryptography (e.g. RbNaCl::Box)
7
+ #
8
+ # Objects of the Point class represent points on Edwards curves. NaCl
9
+ # defines a base point (the "standard group element") which we can
10
+ # multiply by an arbitrary integer. This is how NaCl computes public
11
+ # keys from private keys.
12
+ class Curve25519
13
+ # NaCl's Curve25519 base point (a.k.a. standard group element), serialized as hex
14
+ STANDARD_GROUP_ELEMENT = ["0900000000000000000000000000000000000000000000000000000000000000"].pack("H*").freeze
15
+
16
+ # Order of the standard group
17
+ STANDARD_GROUP_ORDER = 2**252 + 27742317777372353535851937790883648493
18
+
19
+ include KeyComparator
20
+ include Serializable
21
+
22
+ extend Sodium
23
+
24
+ sodium_type :scalarmult
25
+ sodium_primitive :curve25519
26
+
27
+ sodium_function :scalarmult_curve25519,
28
+ :crypto_scalarmult_curve25519,
29
+ [:pointer, :pointer, :pointer]
30
+
31
+ # Number of bytes in a scalar on this curve
32
+ SCALARBYTES = 32
33
+ BYTES = 32
34
+
35
+ # Number of bytes in a scalar on this curve
36
+
37
+ # Creates a new Point from the given serialization
38
+ #
39
+ # @param [String] point location of a group element (32-bytes)
40
+ #
41
+ # @return [RbNaCl::Point] the Point at this location
42
+ def initialize(point)
43
+ @point = point.to_str
44
+
45
+ # FIXME: really should have a separate constant here for group element size
46
+ # Group elements and scalars are both 32-bits, but that's for convenience
47
+ Util.check_length(@point, SCALARBYTES, "group element")
48
+ end
49
+
50
+ # Multiply the given integer by this point
51
+ # This ordering is a bit confusing because traditionally the point
52
+ # would be the right-hand operand.
53
+ #
54
+ # @param [String] integer value to multiply with this Point (32-bytes)
55
+ #
56
+ # @return [RbNaCl::Point] result as a Point object
57
+ def mult(integer, encoding = :raw)
58
+ integer = integer.to_str
59
+ Util.check_length(integer, SCALARBYTES, "integer")
60
+
61
+ result = Util.zeros(SCALARBYTES)
62
+ self.class.scalarmult_curve25519(result, integer, @point)
63
+
64
+ self.class.new(result)
65
+ end
66
+
67
+ # Return the point serialized as bytes
68
+ #
69
+ # @return [String] 32-byte string representing this point
70
+ def to_bytes; @point; end
71
+
72
+ @base_point = new(STANDARD_GROUP_ELEMENT)
73
+
74
+ # NaCl's standard base point for all Curve25519 public keys
75
+ #
76
+ # @return [RbNaCl::Point] standard base point (a.k.a. standard group element)
77
+ def self.base; @base_point; end
78
+ def self.base_point; @base_point; end
79
+ end
80
+ end
81
+ end