rbnacl 1.1.0 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -5
  3. data/CHANGES.md +15 -0
  4. data/Gemfile +4 -1
  5. data/Guardfile +8 -0
  6. data/README.md +52 -3
  7. data/lib/rbnacl.rb +65 -29
  8. data/lib/rbnacl/auth.rb +14 -18
  9. data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +185 -0
  10. data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/private_key.rb +26 -23
  11. data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key.rb +13 -12
  12. data/lib/rbnacl/group_elements/curve25519.rb +81 -0
  13. data/lib/rbnacl/hash.rb +30 -14
  14. data/lib/rbnacl/hash/blake2b.rb +57 -0
  15. data/lib/rbnacl/hash/sha256.rb +15 -0
  16. data/lib/rbnacl/hash/sha512.rb +15 -0
  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 +8 -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 +59 -40
  27. data/lib/rbnacl/serializable.rb +4 -12
  28. data/lib/rbnacl/signatures/ed25519.rb +15 -0
  29. data/lib/rbnacl/signatures/ed25519/signing_key.rb +104 -0
  30. data/lib/rbnacl/signatures/ed25519/verify_key.rb +91 -0
  31. data/lib/rbnacl/sodium.rb +43 -0
  32. data/lib/rbnacl/test_vectors.rb +34 -1
  33. data/lib/rbnacl/util.rb +52 -7
  34. data/lib/rbnacl/version.rb +2 -2
  35. data/rbnacl.gemspec +3 -6
  36. data/spec/rbnacl/{auth/one_time_spec.rb → authenticators/poly1305_spec.rb} +2 -2
  37. data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb +65 -0
  38. data/spec/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key_spec.rb +10 -13
  39. data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +39 -0
  40. data/spec/rbnacl/{point_spec.rb → group_element_spec.rb} +6 -8
  41. data/spec/rbnacl/hash/blake2b_spec.rb +26 -0
  42. data/spec/rbnacl/hash_spec.rb +13 -33
  43. data/spec/rbnacl/hmac/sha256_spec.rb +2 -2
  44. data/spec/rbnacl/hmac/sha512256_spec.rb +2 -2
  45. data/spec/rbnacl/random_nonce_box_spec.rb +21 -26
  46. data/spec/rbnacl/random_spec.rb +3 -3
  47. data/spec/rbnacl/secret_box_spec.rb +6 -6
  48. data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +30 -0
  49. data/spec/rbnacl/signatures/ed25519/verify_key_spec.rb +39 -0
  50. data/spec/rbnacl/util_spec.rb +67 -53
  51. data/spec/shared/authenticator.rb +36 -54
  52. data/spec/shared/box.rb +10 -10
  53. data/spec/shared/key_equality.rb +3 -3
  54. data/spec/shared/serializable.rb +17 -0
  55. data/spec/spec_helper.rb +14 -16
  56. data/tasks/rspec.rake +1 -0
  57. metadata +42 -67
  58. checksums.yaml.gz.sig +0 -0
  59. data.tar.gz.sig +0 -3
  60. data/lib/rbnacl/box.rb +0 -171
  61. data/lib/rbnacl/encoder.rb +0 -44
  62. data/lib/rbnacl/encoders/base32.rb +0 -33
  63. data/lib/rbnacl/encoders/base64.rb +0 -30
  64. data/lib/rbnacl/encoders/hex.rb +0 -30
  65. data/lib/rbnacl/encoders/raw.rb +0 -12
  66. data/lib/rbnacl/keys/signing_key.rb +0 -95
  67. data/lib/rbnacl/keys/verify_key.rb +0 -96
  68. data/lib/rbnacl/nacl.rb +0 -146
  69. data/lib/rbnacl/point.rb +0 -70
  70. data/lib/rbnacl/secret_box.rb +0 -119
  71. data/spec/rbnacl/box_spec.rb +0 -42
  72. data/spec/rbnacl/encoder_spec.rb +0 -14
  73. data/spec/rbnacl/encoders/base32_spec.rb +0 -16
  74. data/spec/rbnacl/encoders/base64_spec.rb +0 -15
  75. data/spec/rbnacl/encoders/hex_spec.rb +0 -15
  76. data/spec/rbnacl/keys/private_key_spec.rb +0 -68
  77. data/spec/rbnacl/keys/signing_key_spec.rb +0 -39
  78. data/spec/rbnacl/keys/verify_key_spec.rb +0 -51
  79. metadata.gz.sig +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f8462f580b5f1517e510c7cf5137b4dc5edec1f
4
- data.tar.gz: e6ef35925227eeb5e49edb8868ab1f375002fa3a
3
+ metadata.gz: 2ba5a3248fe87dd5d2f784f29857ff1d7d26e631
4
+ data.tar.gz: b61bd66e86e6b2bce75ed52d87d0a706df5626b6
5
5
  SHA512:
6
- metadata.gz: 3f66ffdf3087fd9f5b77f85c0e87f68825ed7c9c4cfe07c45d37cab48f299971cd4e07e0a443dde9fa7d7bf245df0834eda82cc4a9f1c4afc52c10cc0602b184
7
- data.tar.gz: a25f2a0fbed4b8b09a9c8bbb4e2d4029e0327684483b1aabf7f2ac8d7023cab716b51a78a38c5531c786f9a143ad6b8c5176a6aafa27ca6347a34f4379aaf06c
6
+ metadata.gz: ed12ef065cb24120b4ff6329026ea69bb560736f6ae6df76534fd064fb862251f29d137b8a8506ed35be67965d610b2cd3b70196253a72da645d3001a3cb7ceb
7
+ data.tar.gz: ea66f56eadd856e610761ecb031b95a5163e7e99d6127b2798126fa2dbf9998bfd53fd9c6cf9d245511f3ba65d70d3af91313f7f01f19bd35a642f212a45ca12
@@ -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,18 @@
1
+ 2.0.0.pre
2
+ ---------
3
+ * ZOMG LOTS OF STUFF! We should make we get it all added to this file!
4
+ * Add encrypt/decrypt aliases for Crypto::RandomNonceBox
5
+ * Rename Crypto module to RbNaCl module
6
+ * RbNaCl::VerifyKey#verify operand order was reversed. New operand order is
7
+ signature, message instead of message, signature
8
+
9
+ 1.1.0 (2013-04-19)
10
+ ------------------
11
+
12
+ * Provide API for querying primitives and details about them, such as key
13
+ lengths, nonce lengths, etc.
14
+ * Fixed bug on passing null bytes to sha256, sha512 functions.
15
+
1
16
  1.0.0 (2013-03-08)
2
17
  ------------------
3
18
  * 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
@@ -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.
@@ -1,5 +1,22 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ require "rbnacl/version"
3
+ require "rbnacl/sodium"
4
+ require "rbnacl/serializable"
5
+ require "rbnacl/key_comparator"
6
+ require "rbnacl/auth"
7
+ require "rbnacl/util"
8
+ require "rbnacl/random"
9
+ require "rbnacl/random_nonce_box"
10
+ require "rbnacl/test_vectors"
11
+ require "rbnacl/init"
12
+
13
+ module RbNaCl
14
+ REQUIRED_LIBSODIUM_VERSION = "0.4.5"
15
+
16
+ if Util.sodium_version_string < REQUIRED_LIBSODIUM_VERSION
17
+ raise "Sorry, you need to install libsodium #{REQUIRED_LIBSODIUM_VERSION}+. You have #{Util.sodium_version_string} installed"
18
+ end
19
+
3
20
  # Oh no, something went wrong!
4
21
  #
5
22
  # This indicates a failure in the operation of a cryptographic primitive such
@@ -18,35 +35,54 @@ module Crypto
18
35
  # This indicates that an attempt has been made to use something (probably a key)
19
36
  # with an incorrect primitive
20
37
  class IncorrectPrimitiveError < ArgumentError; end
21
- end
22
38
 
23
- # TIMTOWTDI!
24
- RbNaCl = Crypto
39
+ # The signature was forged or otherwise corrupt
40
+ class BadSignatureError < CryptoError; end
25
41
 
26
- require "rbnacl/nacl"
27
- require "rbnacl/version"
28
- require "rbnacl/serializable"
29
- require "rbnacl/keys/key_comparator"
30
- require "rbnacl/keys/private_key"
31
- require "rbnacl/keys/public_key"
32
- require "rbnacl/keys/signing_key"
33
- require "rbnacl/keys/verify_key"
34
- require "rbnacl/box"
35
- require "rbnacl/secret_box"
36
- require "rbnacl/hash"
37
- require "rbnacl/util"
38
- require "rbnacl/auth"
39
- require "rbnacl/hmac/sha512256"
40
- require "rbnacl/hmac/sha256"
41
- require "rbnacl/auth/one_time"
42
- require "rbnacl/random"
43
- require "rbnacl/encoder"
44
- require "rbnacl/encoders/base64"
45
- require "rbnacl/encoders/hex"
46
- require "rbnacl/encoders/raw"
47
- require "rbnacl/point"
48
- require "rbnacl/random_nonce_box"
49
- require "rbnacl/test_vectors"
42
+ # Public Key Encryption (Box): Curve25519XSalsa20Poly1305
43
+ require "rbnacl/boxes/curve25519xsalsa20poly1305"
44
+ require "rbnacl/boxes/curve25519xsalsa20poly1305/private_key"
45
+ require "rbnacl/boxes/curve25519xsalsa20poly1305/public_key"
46
+
47
+ # Secret Key Encryption (SecretBox): XSalsa20Poly1305
48
+ require "rbnacl/secret_boxes/xsalsa20poly1305"
49
+
50
+ # Digital Signatures: Ed25519
51
+ require "rbnacl/signatures/ed25519"
52
+ require "rbnacl/signatures/ed25519/signing_key"
53
+ require "rbnacl/signatures/ed25519/verify_key"
54
+
55
+ # Group Elements: Curve25519
56
+ require "rbnacl/group_elements/curve25519"
57
+
58
+ # One-time Authentication: Poly1305
59
+ require "rbnacl/one_time_auths/poly1305"
60
+
61
+ # Hash functions: SHA256/512 and Blake2b
62
+ require "rbnacl/hash"
63
+ require "rbnacl/hash/sha256"
64
+ require "rbnacl/hash/sha512"
65
+ require "rbnacl/hash/blake2b"
66
+
67
+ # HMAC: SHA256 and SHA512256
68
+ require "rbnacl/hmac/sha256"
69
+ require "rbnacl/hmac/sha512256"
70
+
71
+ #
72
+ # Bind aliases used by the public API
73
+ #
74
+ Box = Boxes::Curve25519XSalsa20Poly1305
75
+ PrivateKey = Boxes::Curve25519XSalsa20Poly1305::PrivateKey
76
+ PublicKey = Boxes::Curve25519XSalsa20Poly1305::PublicKey
77
+ SecretBox = SecretBoxes::XSalsa20Poly1305
78
+ SigningKey = Signatures::Ed25519::SigningKey
79
+ VerifyKey = Signatures::Ed25519::VerifyKey
80
+ GroupElement = GroupElements::Curve25519
81
+ OneTimeAuth = OneTimeAuths::Poly1305
82
+ end
83
+
84
+ # Select platform-optimized versions of algorithms
85
+ Thread.exclusive { RbNaCl::Init.sodium_init }
50
86
 
51
87
  # Perform self test on load
52
- require "rbnacl/self_test"
88
+ require "rbnacl/self_test" unless $RBNACL_SELF_TEST == false
@@ -1,5 +1,5 @@
1
1
  # encoding: binary
2
- module Crypto
2
+ module RbNaCl
3
3
  # Secret Key Authenticators
4
4
  #
5
5
  # These provide a means of verifying the integrity of a message, but only
@@ -18,10 +18,8 @@ module Crypto
18
18
  # A new authenticator, ready for auth and verification
19
19
  #
20
20
  # @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")
21
+ def initialize(key)
22
+ @key = Util.check_string(key, key_bytes, "#{self.class} key")
25
23
  end
26
24
 
27
25
  # Compute authenticator for message
@@ -37,38 +35,36 @@ module Crypto
37
35
  # Verifies the given authenticator with the message.
38
36
  #
39
37
  # @param [#to_str] key the key used for the authenticator
40
- # @param [#to_str] message the message to be authenticated
41
38
  # @param [#to_str] authenticator to be checked
39
+ # @param [#to_str] message the message to be authenticated
42
40
  #
43
41
  # @return [Boolean] Was it valid?
44
- def self.verify(key, message, authenticator)
45
- new(key).verify(message, authenticator)
42
+ def self.verify(key, authenticator, message)
43
+ new(key).verify(authenticator, message)
46
44
  end
47
45
 
48
46
  # Compute authenticator for message
49
47
  #
50
48
  # @param [#to_str] message the message to authenticate
51
- # @param [#to_sym] authenticator_encoding format of the authenticator (default raw)
52
49
  #
53
50
  # @return [String] The authenticator in the requested encoding (default raw)
54
- def auth(message, authenticator_encoding = :raw)
51
+ def auth(message)
55
52
  authenticator = Util.zeros(tag_bytes)
56
53
  message = message.to_str
57
- compute_authenticator(message, authenticator)
58
- Encoder[authenticator_encoding].encode(authenticator)
54
+ compute_authenticator(authenticator, message)
55
+ authenticator
59
56
  end
60
57
 
61
58
  # Verifies the given authenticator with the message.
62
59
  #
63
60
  # @param [#to_str] authenticator to be checked
64
61
  # @param [#to_str] message the message to be authenticated
65
- # @param [#to_sym] authenticator_encoding format of the authenticator (default raw)
66
62
  #
67
63
  # @return [Boolean] Was it valid?
68
- def verify(message, authenticator, authenticator_encoding = :raw)
69
- auth = Encoder[authenticator_encoding].decode(authenticator)
64
+ def verify(authenticator, message)
65
+ auth = authenticator.to_s
70
66
  return false unless auth.bytesize == tag_bytes
71
- verify_message(message, auth)
67
+ verify_message(auth, message)
72
68
  end
73
69
 
74
70
  # The crypto primitive for this authenticator instance
@@ -99,7 +95,7 @@ module Crypto
99
95
  def tag_bytes; self.class.tag_bytes; end
100
96
 
101
97
  private
102
- def compute_authenticator(message, authenticator); raise NotImplementedError; end
103
- def verify_message(message, authenticator); raise NotImplementedError; end
98
+ def compute_authenticator(authenticator, message); raise NotImplementedError; end
99
+ def verify_message(authenticator, message); raise NotImplementedError; end
104
100
  end
105
101
  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