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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -5
- data/CHANGES.md +15 -0
- data/Gemfile +4 -1
- data/Guardfile +8 -0
- data/README.md +52 -3
- data/lib/rbnacl.rb +65 -29
- data/lib/rbnacl/auth.rb +14 -18
- data/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb +185 -0
- data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/private_key.rb +26 -23
- data/lib/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key.rb +13 -12
- data/lib/rbnacl/group_elements/curve25519.rb +81 -0
- data/lib/rbnacl/hash.rb +30 -14
- data/lib/rbnacl/hash/blake2b.rb +57 -0
- data/lib/rbnacl/hash/sha256.rb +15 -0
- data/lib/rbnacl/hash/sha512.rb +15 -0
- data/lib/rbnacl/hmac/sha256.rb +19 -17
- data/lib/rbnacl/hmac/sha512256.rb +18 -19
- data/lib/rbnacl/init.rb +10 -0
- data/lib/rbnacl/{keys/key_comparator.rb → key_comparator.rb} +1 -1
- data/lib/rbnacl/{auth/one_time.rb → one_time_auths/poly1305.rb} +21 -19
- data/lib/rbnacl/rake_tasks.rb +7 -6
- data/lib/rbnacl/random.rb +8 -3
- data/lib/rbnacl/random_nonce_box.rb +9 -14
- data/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb +125 -0
- data/lib/rbnacl/self_test.rb +59 -40
- data/lib/rbnacl/serializable.rb +4 -12
- data/lib/rbnacl/signatures/ed25519.rb +15 -0
- data/lib/rbnacl/signatures/ed25519/signing_key.rb +104 -0
- data/lib/rbnacl/signatures/ed25519/verify_key.rb +91 -0
- data/lib/rbnacl/sodium.rb +43 -0
- data/lib/rbnacl/test_vectors.rb +34 -1
- data/lib/rbnacl/util.rb +52 -7
- data/lib/rbnacl/version.rb +2 -2
- data/rbnacl.gemspec +3 -6
- data/spec/rbnacl/{auth/one_time_spec.rb → authenticators/poly1305_spec.rb} +2 -2
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb +65 -0
- data/spec/rbnacl/{keys → boxes/curve25519xsalsa20poly1305}/public_key_spec.rb +10 -13
- data/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb +39 -0
- data/spec/rbnacl/{point_spec.rb → group_element_spec.rb} +6 -8
- data/spec/rbnacl/hash/blake2b_spec.rb +26 -0
- data/spec/rbnacl/hash_spec.rb +13 -33
- data/spec/rbnacl/hmac/sha256_spec.rb +2 -2
- data/spec/rbnacl/hmac/sha512256_spec.rb +2 -2
- data/spec/rbnacl/random_nonce_box_spec.rb +21 -26
- data/spec/rbnacl/random_spec.rb +3 -3
- data/spec/rbnacl/secret_box_spec.rb +6 -6
- data/spec/rbnacl/signatures/ed25519/signing_key_spec.rb +30 -0
- data/spec/rbnacl/signatures/ed25519/verify_key_spec.rb +39 -0
- data/spec/rbnacl/util_spec.rb +67 -53
- data/spec/shared/authenticator.rb +36 -54
- data/spec/shared/box.rb +10 -10
- data/spec/shared/key_equality.rb +3 -3
- data/spec/shared/serializable.rb +17 -0
- data/spec/spec_helper.rb +14 -16
- data/tasks/rspec.rake +1 -0
- metadata +42 -67
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -3
- data/lib/rbnacl/box.rb +0 -171
- data/lib/rbnacl/encoder.rb +0 -44
- data/lib/rbnacl/encoders/base32.rb +0 -33
- data/lib/rbnacl/encoders/base64.rb +0 -30
- data/lib/rbnacl/encoders/hex.rb +0 -30
- data/lib/rbnacl/encoders/raw.rb +0 -12
- data/lib/rbnacl/keys/signing_key.rb +0 -95
- data/lib/rbnacl/keys/verify_key.rb +0 -96
- data/lib/rbnacl/nacl.rb +0 -146
- data/lib/rbnacl/point.rb +0 -70
- data/lib/rbnacl/secret_box.rb +0 -119
- data/spec/rbnacl/box_spec.rb +0 -42
- data/spec/rbnacl/encoder_spec.rb +0 -14
- data/spec/rbnacl/encoders/base32_spec.rb +0 -16
- data/spec/rbnacl/encoders/base64_spec.rb +0 -15
- data/spec/rbnacl/encoders/hex_spec.rb +0 -15
- data/spec/rbnacl/keys/private_key_spec.rb +0 -68
- data/spec/rbnacl/keys/signing_key_spec.rb +0 -39
- data/spec/rbnacl/keys/verify_key_spec.rb +0 -51
- metadata.gz.sig +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ba5a3248fe87dd5d2f784f29857ff1d7d26e631
|
4
|
+
data.tar.gz: b61bd66e86e6b2bce75ed52d87d0a706df5626b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed12ef065cb24120b4ff6329026ea69bb560736f6ae6df76534fd064fb862251f29d137b8a8506ed35be67965d610b2cd3b70196253a72da645d3001a3cb7ceb
|
7
|
+
data.tar.gz: ea66f56eadd856e610761ecb031b95a5163e7e99d6127b2798126fa2dbf9998bfd53fd9c6cf9d245511f3ba65d70d3af91313f7f01f19bd35a642f212a45ca12
|
data/.travis.yml
CHANGED
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
data/Guardfile
ADDED
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
|
260
|
+
Copyright (c) 2013 Jonathan Stott, Tony Arcieri.
|
212
261
|
Distributed under the MIT License. See LICENSE.txt for further details.
|
data/lib/rbnacl.rb
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# encoding: binary
|
2
|
-
|
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
|
-
#
|
24
|
-
|
39
|
+
# The signature was forged or otherwise corrupt
|
40
|
+
class BadSignatureError < CryptoError; end
|
25
41
|
|
26
|
-
|
27
|
-
require "rbnacl/
|
28
|
-
require "rbnacl/
|
29
|
-
require "rbnacl/
|
30
|
-
|
31
|
-
|
32
|
-
require "rbnacl/
|
33
|
-
|
34
|
-
|
35
|
-
require "rbnacl/
|
36
|
-
require "rbnacl/
|
37
|
-
require "rbnacl/
|
38
|
-
|
39
|
-
|
40
|
-
require "rbnacl/
|
41
|
-
|
42
|
-
|
43
|
-
require "rbnacl/
|
44
|
-
|
45
|
-
|
46
|
-
require "rbnacl/
|
47
|
-
require "rbnacl/
|
48
|
-
require "rbnacl/
|
49
|
-
require "rbnacl/
|
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
|
data/lib/rbnacl/auth.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: binary
|
2
|
-
module
|
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
|
-
|
22
|
-
|
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,
|
45
|
-
new(key).verify(
|
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
|
51
|
+
def auth(message)
|
55
52
|
authenticator = Util.zeros(tag_bytes)
|
56
53
|
message = message.to_str
|
57
|
-
compute_authenticator(
|
58
|
-
|
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(
|
69
|
-
auth =
|
64
|
+
def verify(authenticator, message)
|
65
|
+
auth = authenticator.to_s
|
70
66
|
return false unless auth.bytesize == tag_bytes
|
71
|
-
verify_message(
|
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(
|
103
|
-
def verify_message(
|
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
|