rbnacl 1.1.0 → 2.0.0.pre

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 (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