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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.travis.yml +1 -5
- data/CHANGES.md +27 -0
- data/Gemfile +4 -1
- data/Guardfile +8 -0
- data/README.md +52 -3
- data/lib/rbnacl/auth.rb +22 -19
- 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/boxes/curve25519xsalsa20poly1305.rb +185 -0
- data/lib/rbnacl/group_elements/curve25519.rb +81 -0
- data/lib/rbnacl/hash/blake2b.rb +64 -0
- data/lib/rbnacl/hash/sha256.rb +15 -0
- data/lib/rbnacl/hash/sha512.rb +15 -0
- data/lib/rbnacl/hash.rb +30 -14
- 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 +12 -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 +67 -43
- data/lib/rbnacl/serializable.rb +4 -12
- data/lib/rbnacl/signatures/ed25519/signing_key.rb +104 -0
- data/lib/rbnacl/signatures/ed25519/verify_key.rb +78 -0
- data/lib/rbnacl/signatures/ed25519.rb +15 -0
- data/lib/rbnacl/sodium/version.rb +23 -0
- data/lib/rbnacl/sodium.rb +43 -0
- data/lib/rbnacl/test_vectors.rb +34 -1
- data/lib/rbnacl/util.rb +50 -7
- data/lib/rbnacl/version.rb +2 -2
- data/lib/rbnacl.rb +64 -29
- data/rbnacl.gemspec +6 -5
- 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 +30 -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 -55
- 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 +15 -16
- data/tasks/rspec.rake +1 -0
- data.tar.gz.sig +2 -3
- metadata +41 -42
- metadata.gz.sig +2 -2
- 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
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
�. �r_Q���; �|��A�;e�(�zX#�u?���ݛ�Zܻ�@c�ךk�����ɛ�ID>����ߣg�J����4
|
|
2
|
+
%Wh���h�o�ҟ�����,�W�,��˥�{�tw{#�Bk\�
|
data/lib/rbnacl/box.rb
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
# The Box class boxes and unboxes messages between a pair of keys
|
|
4
|
-
#
|
|
5
|
-
# This class uses the given public and secret keys to derive a shared key,
|
|
6
|
-
# which is used with the nonce given to encrypt the given messages and
|
|
7
|
-
# decrypt the given ciphertexts. The same shared key will generated from
|
|
8
|
-
# both pairing of keys, so given two keypairs belonging to alice (pkalice,
|
|
9
|
-
# skalice) and bob(pkbob, skbob), the key derived from (pkalice, skbob) with
|
|
10
|
-
# equal that from (pkbob, skalice). This is how the system works:
|
|
11
|
-
#
|
|
12
|
-
# @example
|
|
13
|
-
# # On bob's system
|
|
14
|
-
# bobkey = Crypto::PrivateKey.generate
|
|
15
|
-
# #=> #<Crypto::PrivateKey ...>
|
|
16
|
-
#
|
|
17
|
-
# # send bobkey.public_key to alice
|
|
18
|
-
# # recieve alice's public key, alicepk
|
|
19
|
-
# # NB: This is actually the hard part of the system. How to do it securely
|
|
20
|
-
# # is left as an exercise to for the reader.
|
|
21
|
-
# alice_pubkey = "..."
|
|
22
|
-
#
|
|
23
|
-
# # make a box
|
|
24
|
-
# alicebob_box = Crypto::Box.new(alice_pubkey, bobkey)
|
|
25
|
-
# #=> #<Crypto::Box ...>
|
|
26
|
-
#
|
|
27
|
-
# # encrypt a message to alice
|
|
28
|
-
# cipher_text = alicebob_box.box("A bad example of a nonce", "Hello, Alice!")
|
|
29
|
-
# #=> "..." # a string of bytes, 29 bytes long
|
|
30
|
-
#
|
|
31
|
-
# # send ["A bad example of a nonce", cipher_text] to alice
|
|
32
|
-
# # note that nonces don't have to be secret
|
|
33
|
-
# # receive [nonce, cipher_text_to_bob] from alice
|
|
34
|
-
#
|
|
35
|
-
# # decrypt the reply
|
|
36
|
-
# # Alice has been a little more sensible than bob, and has a random nonce
|
|
37
|
-
# # that is too fiddly to type here. But there are other choices than just
|
|
38
|
-
# # random
|
|
39
|
-
# plain_text = alicebob_box.open(nonce, cipher_text_to_bob)
|
|
40
|
-
# #=> "Hey there, Bob!"
|
|
41
|
-
#
|
|
42
|
-
# # we have a new message!
|
|
43
|
-
# # But Eve has tampered with this message, by flipping some bytes around!
|
|
44
|
-
# # [nonce2, cipher_text_to_bob_honest_love_eve]
|
|
45
|
-
# alicebob_box.open(nonce2, cipher_text_to_bob_honest_love_eve)
|
|
46
|
-
#
|
|
47
|
-
# # BOOM!
|
|
48
|
-
# # Bob gets a Crypto::CryptoError to deal with!
|
|
49
|
-
#
|
|
50
|
-
# It is VITALLY important that the nonce is a nonce, i.e. it is a number used
|
|
51
|
-
# only once for any given pair of keys. If you fail to do this, you
|
|
52
|
-
# compromise the privacy of the the messages encrypted. Also, bear in mind
|
|
53
|
-
# the property mentioned just above. Give your nonces a different prefix, or
|
|
54
|
-
# have one side use an odd counter and one an even counter. Just make sure
|
|
55
|
-
# they are different.
|
|
56
|
-
#
|
|
57
|
-
# The ciphertexts generated by this class include a 16-byte authenticator which
|
|
58
|
-
# is checked as part of the decryption. An invalid authenticator will cause
|
|
59
|
-
# the unbox function to raise. The authenticator is not a signature. Once
|
|
60
|
-
# you've looked in the box, you've demonstrated the ability to create
|
|
61
|
-
# arbitrary valid messages, so messages you send are repudiatable. For
|
|
62
|
-
# non-repudiatable messages, sign them before or after encryption.
|
|
63
|
-
class Box
|
|
64
|
-
|
|
65
|
-
# Number of bytes in a Box nonce
|
|
66
|
-
NONCEBYTES = NaCl::CURVE25519_XSALSA20_POLY1305_BOX_NONCEBYTES
|
|
67
|
-
|
|
68
|
-
# Create a new Box
|
|
69
|
-
#
|
|
70
|
-
# Sets up the Box for deriving the shared key and encrypting and
|
|
71
|
-
# decrypting messages.
|
|
72
|
-
#
|
|
73
|
-
# @param public_key [String,Crypto::PublicKey] The public key to encrypt to
|
|
74
|
-
# @param private_key [String,Crypto::PrivateKey] The private key to encrypt with
|
|
75
|
-
# @param encoding [Symbol] Parse keys from the given encoding
|
|
76
|
-
#
|
|
77
|
-
# @raise [Crypto::LengthError] on invalid keys
|
|
78
|
-
#
|
|
79
|
-
# @return [Crypto::Box] The new Box, ready to use
|
|
80
|
-
def initialize(public_key, private_key, encoding = :raw)
|
|
81
|
-
@public_key = PublicKey === public_key ? public_key : PublicKey.new(public_key, encoding)
|
|
82
|
-
@private_key = PrivateKey === private_key ? private_key : PrivateKey.new(private_key, encoding)
|
|
83
|
-
raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Encrypts a message
|
|
87
|
-
#
|
|
88
|
-
# Encrypts the message with the given nonce to the keypair set up when
|
|
89
|
-
# initializing the class. Make sure the nonce is unique for any given
|
|
90
|
-
# keypair, or you might as well just send plain text.
|
|
91
|
-
#
|
|
92
|
-
# This function takes care of the padding required by the NaCL C API.
|
|
93
|
-
#
|
|
94
|
-
# @param nonce [String] A 24-byte string containing the nonce.
|
|
95
|
-
# @param message [String] The message to be encrypted.
|
|
96
|
-
#
|
|
97
|
-
# @raise [Crypto::LengthError] If the nonce is not valid
|
|
98
|
-
#
|
|
99
|
-
# @return [String] The ciphertext without the nonce prepended (BINARY encoded)
|
|
100
|
-
def box(nonce, message)
|
|
101
|
-
Util.check_length(nonce, nonce_bytes, "Nonce")
|
|
102
|
-
msg = Util.prepend_zeros(NaCl::ZEROBYTES, message)
|
|
103
|
-
ct = Util.zeros(msg.bytesize)
|
|
104
|
-
|
|
105
|
-
NaCl.crypto_box_curve25519_xsalsa20_poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
|
|
106
|
-
Util.remove_zeros(NaCl::BOXZEROBYTES, ct)
|
|
107
|
-
end
|
|
108
|
-
alias encrypt box
|
|
109
|
-
|
|
110
|
-
# Decrypts a ciphertext
|
|
111
|
-
#
|
|
112
|
-
# Decrypts the ciphertext with the given nonce using the keypair setup when
|
|
113
|
-
# initializing the class.
|
|
114
|
-
#
|
|
115
|
-
# This function takes care of the padding required by the NaCL C API.
|
|
116
|
-
#
|
|
117
|
-
# @param nonce [String] A 24-byte string containing the nonce.
|
|
118
|
-
# @param ciphertext [String] The message to be decrypted.
|
|
119
|
-
#
|
|
120
|
-
# @raise [Crypto::LengthError] If the nonce is not valid
|
|
121
|
-
# @raise [Crypto::CryptoError] If the ciphertext cannot be authenticated.
|
|
122
|
-
#
|
|
123
|
-
# @return [String] The decrypted message (BINARY encoded)
|
|
124
|
-
def open(nonce, ciphertext)
|
|
125
|
-
Util.check_length(nonce, nonce_bytes, "Nonce")
|
|
126
|
-
ct = Util.prepend_zeros(NaCl::BOXZEROBYTES, ciphertext)
|
|
127
|
-
message = Util.zeros(ct.bytesize)
|
|
128
|
-
|
|
129
|
-
NaCl.crypto_box_curve25519_xsalsa20_poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
|
|
130
|
-
Util.remove_zeros(NaCl::ZEROBYTES, message)
|
|
131
|
-
end
|
|
132
|
-
alias decrypt open
|
|
133
|
-
|
|
134
|
-
# The crypto primitive for the box class
|
|
135
|
-
#
|
|
136
|
-
# @return [Symbol] The primitive used
|
|
137
|
-
def self.primitive
|
|
138
|
-
:curve25519_xsalsa20_poly1305
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# The crypto primitive for the box class
|
|
142
|
-
#
|
|
143
|
-
# @return [Symbol] The primitive used
|
|
144
|
-
def primitive
|
|
145
|
-
self.class.primitive
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# The nonce bytes for the box class
|
|
149
|
-
#
|
|
150
|
-
# @return [Integer] The number of bytes in a valid nonce
|
|
151
|
-
def self.nonce_bytes
|
|
152
|
-
NONCEBYTES
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# The nonce bytes for the box instance
|
|
156
|
-
#
|
|
157
|
-
# @return [Integer] The number of bytes in a valid nonce
|
|
158
|
-
def nonce_bytes
|
|
159
|
-
NONCEBYTES
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
private
|
|
163
|
-
def beforenm
|
|
164
|
-
@k ||= begin
|
|
165
|
-
k = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_BOX_BEFORENMBYTES)
|
|
166
|
-
NaCl.crypto_box_curve25519_xsalsa20_poly1305_beforenm(k, @public_key.to_s, @private_key.to_s) || raise(CryptoError, "Failed to derive shared key")
|
|
167
|
-
k
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
end
|
data/lib/rbnacl/encoder.rb
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
# Encoders can be used to serialize or deserialize keys, ciphertexts, hashes,
|
|
4
|
-
# and signatures. To provide an encoder, simply subclass Encoder and call the
|
|
5
|
-
# register class method, then define the encode and decode methods:
|
|
6
|
-
#
|
|
7
|
-
# class CrazysauceEncoder < Crypto::Encoder
|
|
8
|
-
# register :crazysauce
|
|
9
|
-
#
|
|
10
|
-
# def encode(string)
|
|
11
|
-
# ...
|
|
12
|
-
# end
|
|
13
|
-
#
|
|
14
|
-
# def decode(string)
|
|
15
|
-
# ...
|
|
16
|
-
# end
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
# Once an encoder has been registered, an instance of it is available via
|
|
20
|
-
# calling Crypto::Encoder[], e.g. Crypto::Encoder[:hex].encode("foobar")
|
|
21
|
-
#
|
|
22
|
-
class Encoder
|
|
23
|
-
# Hash where encoder objects are stored
|
|
24
|
-
Registry = {}
|
|
25
|
-
|
|
26
|
-
# Register the current class as an encoder
|
|
27
|
-
def self.register(name)
|
|
28
|
-
self[name] = self.new
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Look up an encoder by the given name
|
|
32
|
-
def self.[](name)
|
|
33
|
-
Registry[name.to_sym] or raise ArgumentError, "unsupported encoder: #{name}"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Register an encoder object directly
|
|
37
|
-
def self.[]=(name, obj)
|
|
38
|
-
Registry[name.to_sym] = obj
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def encode(string); raise NotImplementedError, "encoding not implemented"; end
|
|
42
|
-
def decode(string); raise NotImplementedError, "decoding not implemented"; end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
# Requires the base32 gem
|
|
3
|
-
require 'base32'
|
|
4
|
-
|
|
5
|
-
module Crypto
|
|
6
|
-
module Encoders
|
|
7
|
-
# Base64 encoding provider
|
|
8
|
-
#
|
|
9
|
-
# Accessable as Crypto::Encoder[:base64]
|
|
10
|
-
#
|
|
11
|
-
class Base32 < Crypto::Encoder
|
|
12
|
-
register :base32
|
|
13
|
-
|
|
14
|
-
# Base64 encodes a message
|
|
15
|
-
#
|
|
16
|
-
# @param [String] bytes The bytes to encode
|
|
17
|
-
#
|
|
18
|
-
# @return [String] Lovely, elegant "Zooko-style" Base32
|
|
19
|
-
def encode(bytes)
|
|
20
|
-
::Base32.encode(bytes.to_s).downcase
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Hex decodes a message
|
|
24
|
-
#
|
|
25
|
-
# @param [String] base32 string to decode.
|
|
26
|
-
#
|
|
27
|
-
# @return [String] crisp and clean bytes
|
|
28
|
-
def decode(base32)
|
|
29
|
-
::Base32.decode(base32.to_s.upcase)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
module Encoders
|
|
4
|
-
# Base64 encoding provider
|
|
5
|
-
#
|
|
6
|
-
# Accessable as Crypto::Encoder[:base64]
|
|
7
|
-
#
|
|
8
|
-
class Base64 < Crypto::Encoder
|
|
9
|
-
register :base64
|
|
10
|
-
|
|
11
|
-
# Base64 encodes a message
|
|
12
|
-
#
|
|
13
|
-
# @param [String] bytes The bytes to encode
|
|
14
|
-
#
|
|
15
|
-
# @return [String] Clunky old base64
|
|
16
|
-
def encode(bytes)
|
|
17
|
-
[bytes.to_s].pack("m").gsub("\n", '')
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Hex decodes a message
|
|
21
|
-
#
|
|
22
|
-
# @param [String] base64 string to decode.
|
|
23
|
-
#
|
|
24
|
-
# @return [String] crisp and clean bytes
|
|
25
|
-
def decode(base64)
|
|
26
|
-
base64.to_s.unpack("m").first
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
data/lib/rbnacl/encoders/hex.rb
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
module Encoders
|
|
4
|
-
# Hex encoding provider
|
|
5
|
-
#
|
|
6
|
-
# Accessable as Crypto::Encoder[:hex]
|
|
7
|
-
#
|
|
8
|
-
class Hex < Crypto::Encoder
|
|
9
|
-
register :hex
|
|
10
|
-
|
|
11
|
-
# Hex encodes a message
|
|
12
|
-
#
|
|
13
|
-
# @param [String] bytes The bytes to encode
|
|
14
|
-
#
|
|
15
|
-
# @return [String] Tasty, tasty hexidecimal
|
|
16
|
-
def encode(bytes)
|
|
17
|
-
bytes.to_s.unpack("H*").first
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Hex decodes a message
|
|
21
|
-
#
|
|
22
|
-
# @param [String] hex hex to decode.
|
|
23
|
-
#
|
|
24
|
-
# @return [String] crisp and clean bytes
|
|
25
|
-
def decode(hex)
|
|
26
|
-
[hex.to_s].pack("H*")
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
data/lib/rbnacl/encoders/raw.rb
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
module Encoders
|
|
4
|
-
# Raw encoder which only does a string conversion (if necessary)
|
|
5
|
-
class Raw < Crypto::Encoder
|
|
6
|
-
register :raw
|
|
7
|
-
|
|
8
|
-
def encode(bytes); bytes.to_s; end
|
|
9
|
-
def decode(bytes); bytes.to_s; end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
# Private key for producing digital signatures using the Ed25519 algorithm.
|
|
4
|
-
# Ed25519 provides a 128-bit security level, that is to say, all known attacks
|
|
5
|
-
# take at least 2^128 operations, providing the same security level as
|
|
6
|
-
# AES-128, NIST P-256, and RSA-3072.
|
|
7
|
-
#
|
|
8
|
-
# Signing keys are produced from a 32-byte (256-bit) random seed value.
|
|
9
|
-
# This value can be passed into the SigningKey constructoras a String
|
|
10
|
-
# whose bytesize is 32.
|
|
11
|
-
#
|
|
12
|
-
# The public VerifyKey can be computed from the private 32-byte seed value
|
|
13
|
-
# as well, eliminating the need to store a "keypair".
|
|
14
|
-
#
|
|
15
|
-
# SigningKey produces 64-byte (512-bit) signatures. The signatures are
|
|
16
|
-
# deterministic: signing the same message will always produce the same
|
|
17
|
-
# signature. This prevents "entropy failure" seen in other signature
|
|
18
|
-
# algorithms like DSA and ECDSA, where poor random number generators can
|
|
19
|
-
# leak enough information to recover the private key.
|
|
20
|
-
class SigningKey
|
|
21
|
-
include KeyComparator
|
|
22
|
-
include Serializable
|
|
23
|
-
|
|
24
|
-
attr_reader :verify_key
|
|
25
|
-
|
|
26
|
-
# Generate a random SigningKey
|
|
27
|
-
#
|
|
28
|
-
# @return [Crypto::SigningKey] Freshly-generated random SigningKey
|
|
29
|
-
def self.generate
|
|
30
|
-
new Crypto::Random.random_bytes(NaCl::ED25519_SEED_BYTES)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Create a SigningKey from a seed value
|
|
34
|
-
#
|
|
35
|
-
# @param seed [String] Random 32-byte value (i.e. private key)
|
|
36
|
-
# @param encoding [Symbol] Parse seed from the given encoding
|
|
37
|
-
#
|
|
38
|
-
# @return [Crypto::SigningKey] Key which can sign messages
|
|
39
|
-
def initialize(seed, encoding = :raw)
|
|
40
|
-
seed = Encoder[encoding].decode(seed)
|
|
41
|
-
|
|
42
|
-
Util.check_length(seed, NaCl::ED25519_SEED_BYTES, "seed")
|
|
43
|
-
|
|
44
|
-
pk = Util.zeros(NaCl::ED25519_VERIFYKEY_BYTES)
|
|
45
|
-
sk = Util.zeros(NaCl::ED25519_SIGNINGKEY_BYTES)
|
|
46
|
-
|
|
47
|
-
NaCl.crypto_sign_ed25519_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair")
|
|
48
|
-
|
|
49
|
-
@seed, @signing_key = seed, sk
|
|
50
|
-
@verify_key = VerifyKey.new(pk)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Sign a message using this key
|
|
54
|
-
#
|
|
55
|
-
# @param message [String] Message to be signed by this key
|
|
56
|
-
# @param encoding [Symbol] Encode signature in the given format
|
|
57
|
-
#
|
|
58
|
-
# @return [String] Signature as bytes
|
|
59
|
-
def sign(message, encoding = :raw)
|
|
60
|
-
buffer = Util.prepend_zeros(signature_bytes, message)
|
|
61
|
-
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)
|
|
62
|
-
|
|
63
|
-
NaCl.crypto_sign_ed25519(buffer, buffer_len, message, message.bytesize, @signing_key)
|
|
64
|
-
|
|
65
|
-
signature = buffer[0, signature_bytes]
|
|
66
|
-
Encoder[encoding].encode(signature)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Return the raw seed value of this key
|
|
70
|
-
#
|
|
71
|
-
# @return [String] seed used to create this key
|
|
72
|
-
def to_bytes; @seed; end
|
|
73
|
-
|
|
74
|
-
# The crypto primitive the SigningKey class uses for signatures
|
|
75
|
-
#
|
|
76
|
-
# @return [Symbol] The primitive
|
|
77
|
-
def self.primitive; :ed25519; end
|
|
78
|
-
|
|
79
|
-
# The crypto primitive this SigningKey class uses for signatures
|
|
80
|
-
#
|
|
81
|
-
# @return [Symbol] The primitive
|
|
82
|
-
def primitive; self.class.primitive; end
|
|
83
|
-
|
|
84
|
-
# The size of signatures generated by the SigningKey class
|
|
85
|
-
#
|
|
86
|
-
# @return [Integer] The number of bytes in a signature
|
|
87
|
-
def self.signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end
|
|
88
|
-
|
|
89
|
-
# The size of signatures generated by the SigningKey instance
|
|
90
|
-
#
|
|
91
|
-
# @return [Integer] The number of bytes in a signature
|
|
92
|
-
def signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end
|
|
93
|
-
|
|
94
|
-
end
|
|
95
|
-
end
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
module Crypto
|
|
3
|
-
# The signature was forged or otherwise corrupt
|
|
4
|
-
class BadSignatureError < CryptoError; end
|
|
5
|
-
|
|
6
|
-
# The public key counterpart to an Ed25519 SigningKey for producing digital
|
|
7
|
-
# signatures. Like the name says, VerifyKeys can be used to verify that a
|
|
8
|
-
# given digital signature is authentic.
|
|
9
|
-
#
|
|
10
|
-
# For more information on the Ed25519 digital signature system, please see
|
|
11
|
-
# the SigningKey documentation.
|
|
12
|
-
class VerifyKey
|
|
13
|
-
include KeyComparator
|
|
14
|
-
include Serializable
|
|
15
|
-
|
|
16
|
-
# Create a new VerifyKey object from a serialized public key. The key can
|
|
17
|
-
# be decoded from any serialization format supported by the
|
|
18
|
-
# Crypto::Encoding system.
|
|
19
|
-
#
|
|
20
|
-
# @param key [String] Serialized Ed25519 public key
|
|
21
|
-
# @param encoding [Symbol] Parse key from the given encoding
|
|
22
|
-
#
|
|
23
|
-
# @return [Crypto::SigningKey] Key which can sign messages
|
|
24
|
-
def initialize(key, encoding = :raw)
|
|
25
|
-
key = Encoder[encoding].decode(key)
|
|
26
|
-
Util.check_length(key, NaCl::ED25519_VERIFYKEY_BYTES, "key")
|
|
27
|
-
|
|
28
|
-
@key = key
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Create a new VerifyKey object from a serialized public key. The key can
|
|
32
|
-
# be decoded from any serialization format supported by the
|
|
33
|
-
# Crypto::Encoding system.
|
|
34
|
-
#
|
|
35
|
-
# You can remember the argument ordering by "verify message with signature"
|
|
36
|
-
# It's like a legal document, with the signature at the end.
|
|
37
|
-
#
|
|
38
|
-
# @param message [String] Message to be authenticated
|
|
39
|
-
# @param signature [String] Alleged signature to be checked
|
|
40
|
-
# @param signature_encoding [Symbol] Parse signature from the given encoding
|
|
41
|
-
#
|
|
42
|
-
# @return [Boolean] was the signature authentic?
|
|
43
|
-
def verify(message, signature, signature_encoding = :raw)
|
|
44
|
-
signature = Encoder[signature_encoding].decode(signature)
|
|
45
|
-
Util.check_length(signature, signature_bytes, "signature")
|
|
46
|
-
|
|
47
|
-
sig_and_msg = signature + message
|
|
48
|
-
buffer = Util.zeros(sig_and_msg.bytesize)
|
|
49
|
-
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)
|
|
50
|
-
|
|
51
|
-
NaCl.crypto_sign_ed25519_open(buffer, buffer_len, sig_and_msg, sig_and_msg.bytesize, @key)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# "Dangerous" (but probably safer) verify that raises an exception if a
|
|
55
|
-
# signature check fails. This is probably less likely to go unnoticed than
|
|
56
|
-
# an improperly checked verify, as you are forced to deal with the
|
|
57
|
-
# exception explicitly (and failing signature checks are certainly an
|
|
58
|
-
# exceptional condition!)
|
|
59
|
-
#
|
|
60
|
-
# The arguments are otherwise the same as the verify method.
|
|
61
|
-
#
|
|
62
|
-
# @param message [String] Message to be authenticated
|
|
63
|
-
# @param signature [String] Alleged signature to be checked
|
|
64
|
-
# @param signature_encoding [Symbol] Parse signature from the given encoding
|
|
65
|
-
#
|
|
66
|
-
# @return [true] Will raise BadSignatureError if signature check fails
|
|
67
|
-
def verify!(message, signature, signature_encoding = :raw)
|
|
68
|
-
verify(message, signature, signature_encoding) or raise BadSignatureError, "signature was forged/corrupt"
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Return the raw key in byte format
|
|
72
|
-
#
|
|
73
|
-
# @return [String] raw key as bytes
|
|
74
|
-
def to_bytes; @key; end
|
|
75
|
-
|
|
76
|
-
# The crypto primitive the VerifyKey class uses for signatures
|
|
77
|
-
#
|
|
78
|
-
# @return [Symbol] The primitive
|
|
79
|
-
def self.primitive; :ed25519; end
|
|
80
|
-
|
|
81
|
-
# The crypto primitive this VerifyKey class uses for signatures
|
|
82
|
-
#
|
|
83
|
-
# @return [Symbol] The primitive
|
|
84
|
-
def primitive; self.class.primitive; end
|
|
85
|
-
|
|
86
|
-
# The size of signatures verified by the VerifyKey class
|
|
87
|
-
#
|
|
88
|
-
# @return [Integer] The number of bytes in a signature
|
|
89
|
-
def self.signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end
|
|
90
|
-
|
|
91
|
-
# The size of signatures verified by the VerifyKey instance
|
|
92
|
-
#
|
|
93
|
-
# @return [Integer] The number of bytes in a signature
|
|
94
|
-
def signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end
|
|
95
|
-
end
|
|
96
|
-
end
|
data/lib/rbnacl/nacl.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# encoding: binary
|
|
2
|
-
require 'ffi'
|
|
3
|
-
module Crypto
|
|
4
|
-
# This module has all the FFI code hanging off it
|
|
5
|
-
#
|
|
6
|
-
# And that's all it does, really.
|
|
7
|
-
#
|
|
8
|
-
# HERE BE DRAGONS!
|
|
9
|
-
#
|
|
10
|
-
# Do **NOT** use constants and methods defined here. If you do find yourself
|
|
11
|
-
# needing to, that is a bug in RbNaCl and should be reported.
|
|
12
|
-
#
|
|
13
|
-
# @private
|
|
14
|
-
module NaCl
|
|
15
|
-
extend FFI::Library
|
|
16
|
-
ffi_lib 'sodium'
|
|
17
|
-
|
|
18
|
-
# Wraps an NaCl function so it returns a sane value
|
|
19
|
-
#
|
|
20
|
-
# The NaCl functions generally have an integer return value which is 0 in
|
|
21
|
-
# the case of success and below 0 if they failed. This is a bit
|
|
22
|
-
# inconvinient in ruby, where 0 is a truthy value, so this makes them
|
|
23
|
-
# return true/false based on success.
|
|
24
|
-
#
|
|
25
|
-
# @param [Symbol] name Function name that will return true/false
|
|
26
|
-
# @param [Symbol] function Function to attach
|
|
27
|
-
# @param [Array<Symbol>] arguments Array of arguments to the function
|
|
28
|
-
def self.wrap_nacl_function(name, function, arguments)
|
|
29
|
-
module_eval <<-eos, __FILE__, __LINE__ + 1
|
|
30
|
-
attach_function #{function.inspect}, #{arguments.inspect}, :int
|
|
31
|
-
def self.#{name}(*args)
|
|
32
|
-
ret = #{function}(*args)
|
|
33
|
-
ret == 0
|
|
34
|
-
end
|
|
35
|
-
eos
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
SHA256BYTES = 32
|
|
39
|
-
wrap_nacl_function :crypto_hash_sha256,
|
|
40
|
-
:crypto_hash_sha256_ref,
|
|
41
|
-
[:pointer, :pointer, :long_long]
|
|
42
|
-
|
|
43
|
-
SHA512BYTES = 64
|
|
44
|
-
wrap_nacl_function :crypto_hash_sha512,
|
|
45
|
-
:crypto_hash_sha512_ref,
|
|
46
|
-
[:pointer, :pointer, :long_long]
|
|
47
|
-
|
|
48
|
-
CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES = 32
|
|
49
|
-
PUBLICKEYBYTES = CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES
|
|
50
|
-
CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES = 32
|
|
51
|
-
SECRETKEYBYTES = CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES
|
|
52
|
-
wrap_nacl_function :crypto_box_curve25519xsalsa20poly1305_keypair,
|
|
53
|
-
:crypto_box_curve25519xsalsa20poly1305_ref_keypair,
|
|
54
|
-
[:pointer, :pointer]
|
|
55
|
-
|
|
56
|
-
CURVE25519_XSALSA20_POLY1305_BOX_NONCEBYTES = 24
|
|
57
|
-
NONCEBYTES = CURVE25519_XSALSA20_POLY1305_BOX_NONCEBYTES
|
|
58
|
-
ZEROBYTES = 32
|
|
59
|
-
BOXZEROBYTES = 16
|
|
60
|
-
CURVE25519_XSALSA20_POLY1305_BOX_BEFORENMBYTES = 32
|
|
61
|
-
|
|
62
|
-
wrap_nacl_function :crypto_box_curve25519_xsalsa20_poly1305_beforenm,
|
|
63
|
-
:crypto_box_curve25519xsalsa20poly1305_ref_beforenm,
|
|
64
|
-
[:pointer, :pointer, :pointer]
|
|
65
|
-
|
|
66
|
-
wrap_nacl_function :crypto_box_curve25519_xsalsa20_poly1305_afternm,
|
|
67
|
-
:crypto_box_curve25519xsalsa20poly1305_ref_afternm,
|
|
68
|
-
[:pointer, :pointer, :long_long, :pointer, :pointer]
|
|
69
|
-
|
|
70
|
-
wrap_nacl_function :crypto_box_curve25519_xsalsa20_poly1305_open_afternm,
|
|
71
|
-
:crypto_box_curve25519xsalsa20poly1305_ref_open_afternm,
|
|
72
|
-
[:pointer, :pointer, :long_long, :pointer, :pointer]
|
|
73
|
-
|
|
74
|
-
XSALSA20_POLY1305_SECRETBOX_KEYBYTES = 32
|
|
75
|
-
XSALSA20_POLY1305_SECRETBOX_NONCEBYTES = 24
|
|
76
|
-
wrap_nacl_function :crypto_secretbox_xsalsa20poly1305,
|
|
77
|
-
:crypto_secretbox_xsalsa20poly1305_ref,
|
|
78
|
-
[:pointer, :pointer, :long_long, :pointer, :pointer]
|
|
79
|
-
|
|
80
|
-
wrap_nacl_function :crypto_secretbox_xsalsa20poly1305_open,
|
|
81
|
-
:crypto_secretbox_xsalsa20poly1305_ref_open,
|
|
82
|
-
[:pointer, :pointer, :long_long, :pointer, :pointer]
|
|
83
|
-
|
|
84
|
-
HMACSHA512256_KEYBYTES = 32
|
|
85
|
-
HMACSHA512256_BYTES = 32
|
|
86
|
-
wrap_nacl_function :crypto_auth_hmacsha512256,
|
|
87
|
-
:crypto_auth_hmacsha512256_ref,
|
|
88
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
89
|
-
wrap_nacl_function :crypto_auth_hmacsha512256_verify,
|
|
90
|
-
:crypto_auth_hmacsha512256_ref_verify,
|
|
91
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
92
|
-
|
|
93
|
-
HMACSHA256_KEYBYTES = 32
|
|
94
|
-
HMACSHA256_BYTES = 32
|
|
95
|
-
wrap_nacl_function :crypto_auth_hmacsha256,
|
|
96
|
-
:crypto_auth_hmacsha256_ref,
|
|
97
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
98
|
-
wrap_nacl_function :crypto_auth_hmacsha256_verify,
|
|
99
|
-
:crypto_auth_hmacsha256_ref_verify,
|
|
100
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
101
|
-
|
|
102
|
-
ONETIME_KEYBYTES = 32
|
|
103
|
-
ONETIME_BYTES = 16
|
|
104
|
-
wrap_nacl_function :crypto_auth_onetime,
|
|
105
|
-
:crypto_onetimeauth_poly1305_ref,
|
|
106
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
107
|
-
wrap_nacl_function :crypto_auth_onetime_verify,
|
|
108
|
-
:crypto_onetimeauth_poly1305_ref_verify,
|
|
109
|
-
[:pointer, :pointer, :long_long, :pointer]
|
|
110
|
-
|
|
111
|
-
wrap_nacl_function :random_bytes,
|
|
112
|
-
:randombytes,
|
|
113
|
-
[:pointer, :long_long]
|
|
114
|
-
|
|
115
|
-
wrap_nacl_function :crypto_verify_32,
|
|
116
|
-
:crypto_verify_32_ref,
|
|
117
|
-
[:pointer, :pointer]
|
|
118
|
-
wrap_nacl_function :crypto_verify_16,
|
|
119
|
-
:crypto_verify_16_ref,
|
|
120
|
-
[:pointer, :pointer]
|
|
121
|
-
|
|
122
|
-
ED25519_SIGNATUREBYTES = 64
|
|
123
|
-
SIGNATUREBYTES = ED25519_SIGNATUREBYTES
|
|
124
|
-
ED25519_SIGNINGKEY_BYTES = 64
|
|
125
|
-
ED25519_VERIFYKEY_BYTES = 32
|
|
126
|
-
ED25519_SEED_BYTES = 32
|
|
127
|
-
wrap_nacl_function :crypto_sign_ed25519_seed_keypair,
|
|
128
|
-
:crypto_sign_ed25519_ref_seed_keypair,
|
|
129
|
-
[:pointer, :pointer, :pointer]
|
|
130
|
-
|
|
131
|
-
wrap_nacl_function :crypto_sign_ed25519,
|
|
132
|
-
:crypto_sign_ed25519_ref,
|
|
133
|
-
[:pointer, :pointer, :pointer, :long_long, :pointer]
|
|
134
|
-
|
|
135
|
-
wrap_nacl_function :crypto_sign_ed25519_open,
|
|
136
|
-
:crypto_sign_ed25519_ref_open,
|
|
137
|
-
[:pointer, :pointer, :pointer, :long_long, :pointer]
|
|
138
|
-
|
|
139
|
-
ED25519_SCALARBYTES = 32
|
|
140
|
-
SCALARBYTES = ED25519_SCALARBYTES
|
|
141
|
-
|
|
142
|
-
wrap_nacl_function :crypto_scalarmult_curve25519,
|
|
143
|
-
:crypto_scalarmult_curve25519_ref,
|
|
144
|
-
[:pointer, :pointer, :pointer]
|
|
145
|
-
end
|
|
146
|
-
end
|