Skip to content

Commit

Permalink
Merge bc4e9bb into 9afa235
Browse files Browse the repository at this point in the history
  • Loading branch information
namelessjon committed Apr 8, 2013
2 parents 9afa235 + bc4e9bb commit f189da2
Show file tree
Hide file tree
Showing 29 changed files with 356 additions and 160 deletions.
6 changes: 6 additions & 0 deletions lib/rbnacl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ class CryptoError < StandardError; end
# This indicates some argument with an expected length was not that length.
# Since this is probably a cryptographic key, you should check that!
class LengthError < ArgumentError; end

# An incorrect primitive has been passed to a method
#
# This indicates that an attempt has been made to use something (probably a key)
# with an incorrect primitive
class IncorrectPrimitiveError < ArgumentError; end
end

# TIMTOWTDI!
Expand Down
33 changes: 30 additions & 3 deletions lib/rbnacl/auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Auth
# @param [#to_sym] encoding decode key from this format (default raw)
def initialize(key, encoding = :raw)
@key = Encoder[encoding].decode(key)
Util.check_length(@key, self.class::KEYBYTES, "#{self.class} key")
Util.check_length(@key, key_bytes, "#{self.class} key")
end

# Compute authenticator for message
Expand Down Expand Up @@ -52,7 +52,7 @@ def self.verify(key, message, authenticator)
#
# @return [String] The authenticator in the requested encoding (default raw)
def auth(message, authenticator_encoding = :raw)
authenticator = Util.zeros(self.class::BYTES)
authenticator = Util.zeros(tag_bytes)
message = message.to_str
compute_authenticator(message, authenticator)
Encoder[authenticator_encoding].encode(authenticator)
Expand All @@ -67,10 +67,37 @@ def auth(message, authenticator_encoding = :raw)
# @return [Boolean] Was it valid?
def verify(message, authenticator, authenticator_encoding = :raw)
auth = Encoder[authenticator_encoding].decode(authenticator)
return false unless auth.bytesize == self.class::BYTES
return false unless auth.bytesize == tag_bytes
verify_message(message, auth)
end

# The crypto primitive for this authenticator instance
#
# @return [Symbol] The primitive used
def primitive
self.class.primitive
end

# The number of key bytes for this Auth class
#
# @return [Integer] number of key bytes
def self.key_bytes; self::KEYBYTES; end

# The number of key bytes for this Auth instance
#
# @return [Integer] number of key bytes
def key_bytes; self.class.key_bytes; end

# The number bytes in the tag or authenticator from this Auth class
#
# @return [Integer] number of tag bytes
def self.tag_bytes; self::BYTES; end

# The number of bytes in the tag or authenticator for this Auth instance
#
# @return [Integer] number of tag bytes
def tag_bytes; self.class.tag_bytes; end

private
def compute_authenticator(message, authenticator); raise NotImplementedError; end
def verify_message(message, authenticator); raise NotImplementedError; end
Expand Down
7 changes: 7 additions & 0 deletions lib/rbnacl/auth/one_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ class OneTime < self

# Number of bytes in a valid authenticator
BYTES = NaCl::ONETIME_BYTES

# The crypto primitive for the Auth::OneTime class
#
# @return [Symbol] The primitive used
def self.primitive
:poly_1305
end

private
def compute_authenticator(message, authenticator)
Expand Down
50 changes: 40 additions & 10 deletions lib/rbnacl/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ module Crypto
# non-repudiatable messages, sign them before or after encryption.
class Box

# Number of bytes in a Box nonce
NONCEBYTES = NaCl::CURVE25519_XSALSA20_POLY1305_BOX_NONCEBYTES

# Create a new Box
#
# Sets up the Box for deriving the shared key and encrypting and
Expand All @@ -75,10 +78,9 @@ class Box
#
# @return [Crypto::Box] The new Box, ready to use
def initialize(public_key, private_key, encoding = :raw)
@public_key = Encoder[encoding].decode(public_key) if public_key
@private_key = Encoder[encoding].decode(private_key) if private_key
Util.check_length(@public_key, PublicKey::BYTES, "Public key")
Util.check_length(@private_key, PrivateKey::BYTES, "Private key")
@public_key = PublicKey === public_key ? public_key : PublicKey.new(public_key, encoding)
@private_key = PrivateKey === private_key ? private_key : PrivateKey.new(private_key, encoding)
raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
end

# Encrypts a message
Expand All @@ -96,11 +98,11 @@ def initialize(public_key, private_key, encoding = :raw)
#
# @return [String] The ciphertext without the nonce prepended (BINARY encoded)
def box(nonce, message)
Util.check_length(nonce, Crypto::NaCl::NONCEBYTES, "Nonce")
Util.check_length(nonce, nonce_bytes, "Nonce")
msg = Util.prepend_zeros(NaCl::ZEROBYTES, message)
ct = Util.zeros(msg.bytesize)

NaCl.crypto_box_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
NaCl.crypto_box_curve25519_xsalsa20_poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
Util.remove_zeros(NaCl::BOXZEROBYTES, ct)
end
alias encrypt box
Expand All @@ -120,20 +122,48 @@ def box(nonce, message)
#
# @return [String] The decrypted message (BINARY encoded)
def open(nonce, ciphertext)
Util.check_length(nonce, Crypto::NaCl::NONCEBYTES, "Nonce")
Util.check_length(nonce, nonce_bytes, "Nonce")
ct = Util.prepend_zeros(NaCl::BOXZEROBYTES, ciphertext)
message = Util.zeros(ct.bytesize)

NaCl.crypto_box_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
NaCl.crypto_box_curve25519_xsalsa20_poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
Util.remove_zeros(NaCl::ZEROBYTES, message)
end
alias decrypt open

# The crypto primitive for the box class
#
# @return [Symbol] The primitive used
def self.primitive
:curve25519_xsalsa20_poly1305
end

# The crypto primitive for the box class
#
# @return [Symbol] The primitive used
def primitive
self.class.primitive
end

# The nonce bytes for the box class
#
# @return [Integer] The number of bytes in a valid nonce
def self.nonce_bytes
NONCEBYTES
end

# The nonce bytes for the box instance
#
# @return [Integer] The number of bytes in a valid nonce
def nonce_bytes
NONCEBYTES
end

private
def beforenm
@k ||= begin
k = Util.zeros(NaCl::BEFORENMBYTES)
NaCl.crypto_box_beforenm(k, @public_key, @private_key) || raise(CryptoError, "Failed to derive shared key")
k = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_BOX_BEFORENMBYTES)
NaCl.crypto_box_curve25519_xsalsa20_poly1305_beforenm(k, @public_key.to_s, @private_key.to_s) || raise(CryptoError, "Failed to derive shared key")
k
end
end
Expand Down
7 changes: 7 additions & 0 deletions lib/rbnacl/hmac/sha256.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class SHA256 < Auth
# Number of bytes in a valid authenticator
BYTES = NaCl::HMACSHA256_BYTES

# The crypto primitive for the HMAC::SHA256 class
#
# @return [Symbol] The primitive used
def self.primitive
:hmac_sha256
end

private
def compute_authenticator(message, authenticator)
NaCl.crypto_auth_hmacsha256(authenticator, message, message.bytesize, key)
Expand Down
7 changes: 7 additions & 0 deletions lib/rbnacl/hmac/sha512256.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ class SHA512256 < Auth

# Number of bytes in a valid authenticator
BYTES = NaCl::HMACSHA512256_BYTES

# The crypto primitive for the HMAC::SHA512256 class
#
# @return [Symbol] The primitive used
def self.primitive
:hmac_sha512256
end

private
def compute_authenticator(message, authenticator)
Expand Down
23 changes: 19 additions & 4 deletions lib/rbnacl/keys/private_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PrivateKey
include Serializable

# The size of the key, in bytes
BYTES = Crypto::NaCl::SECRETKEYBYTES
BYTES = NaCl::CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES

# Initializes a new PrivateKey for key operations.
#
Expand All @@ -39,9 +39,9 @@ def initialize(private_key, key_encoding = :raw)
#
# @return [Crypto::PrivateKey] A new private key, with the associated public key also set.
def self.generate
pk = Util.zeros(NaCl::PUBLICKEYBYTES)
sk = Util.zeros(NaCl::SECRETKEYBYTES)
NaCl.crypto_box_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair")
pk = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES)
sk = Util.zeros(NaCl::CURVE25519_XSALSA20_POLY1305_SECRETKEY_BYTES)
NaCl.crypto_box_curve25519xsalsa20poly1305_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair")
new(sk)
end

Expand All @@ -58,5 +58,20 @@ def to_bytes
def public_key
@public_key ||= PublicKey.new(Point.base.mult(to_bytes))
end

# The crypto primitive the PrivateKey class is to be used for
#
# @return [Symbol] The primitive
def self.primitive
:curve25519_xsalsa20_poly1305
end

# The crypto primitive this PrivateKey is to be used for.
#
# @return [Symbol] The primitive
def primitive
self.class.primitive
end

end
end
16 changes: 15 additions & 1 deletion lib/rbnacl/keys/public_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class PublicKey
include Serializable

# The size of the key, in bytes
BYTES = Crypto::NaCl::PUBLICKEYBYTES
BYTES = NaCl::CURVE25519_XSALSA20_POLY1305_PUBLICKEY_BYTES

# Initializes a new PublicKey for key operations.
#
Expand All @@ -34,5 +34,19 @@ def initialize(public_key, key_encoding = :raw)
def to_bytes
@public_key
end

# The crypto primitive the PublicKey class is to be used for
#
# @return [Symbol] The primitive
def self.primitive
:curve25519_xsalsa20_poly1305
end

# The crypto primitive this PublicKey is to be used for.
#
# @return [Symbol] The primitive
def primitive
self.class.primitive
end
end
end
39 changes: 30 additions & 9 deletions lib/rbnacl/keys/signing_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class SigningKey
#
# @return [Crypto::SigningKey] Freshly-generated random SigningKey
def self.generate
new Crypto::Random.random_bytes(NaCl::SECRETKEYBYTES)
new Crypto::Random.random_bytes(NaCl::ED25519_SEED_BYTES)
end

# Create a SigningKey from a seed value
Expand All @@ -39,12 +39,12 @@ def self.generate
def initialize(seed, encoding = :raw)
seed = Encoder[encoding].decode(seed)

Util.check_length(seed, NaCl::SECRETKEYBYTES, "seed")
Util.check_length(seed, NaCl::ED25519_SEED_BYTES, "seed")

pk = Util.zeros(NaCl::PUBLICKEYBYTES)
sk = Util.zeros(NaCl::SECRETKEYBYTES * 2)
pk = Util.zeros(NaCl::ED25519_VERIFYKEY_BYTES)
sk = Util.zeros(NaCl::ED25519_SIGNINGKEY_BYTES)

NaCl.crypto_sign_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair")
NaCl.crypto_sign_ed25519_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair")

@seed, @signing_key = seed, sk
@verify_key = VerifyKey.new(pk)
Expand All @@ -55,20 +55,41 @@ def initialize(seed, encoding = :raw)
# @param message [String] Message to be signed by this key
# @param encoding [Symbol] Encode signature in the given format
#
# @return [String] Signature as bytes
# @return [String] Signature as bytes
def sign(message, encoding = :raw)
buffer = Util.prepend_zeros(NaCl::SIGNATUREBYTES, message)
buffer = Util.prepend_zeros(signature_bytes, message)
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)

NaCl.crypto_sign(buffer, buffer_len, message, message.bytesize, @signing_key)
NaCl.crypto_sign_ed25519(buffer, buffer_len, message, message.bytesize, @signing_key)

signature = buffer[0, NaCl::SIGNATUREBYTES]
signature = buffer[0, signature_bytes]
Encoder[encoding].encode(signature)
end

# Return the raw seed value of this key
#
# @return [String] seed used to create this key
def to_bytes; @seed; end

# The crypto primitive the SigningKey class uses for signatures
#
# @return [Symbol] The primitive
def self.primitive; :ed25519; end

# The crypto primitive this SigningKey class uses for signatures
#
# @return [Symbol] The primitive
def primitive; self.class.primitive; end

# The size of signatures generated by the SigningKey class
#
# @return [Integer] The number of bytes in a signature
def self.signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end

# The size of signatures generated by the SigningKey instance
#
# @return [Integer] The number of bytes in a signature
def signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end

end
end
26 changes: 23 additions & 3 deletions lib/rbnacl/keys/verify_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class VerifyKey
# @return [Crypto::SigningKey] Key which can sign messages
def initialize(key, encoding = :raw)
key = Encoder[encoding].decode(key)
Util.check_length(key, NaCl::PUBLICKEYBYTES, "key")
Util.check_length(key, NaCl::ED25519_VERIFYKEY_BYTES, "key")

@key = key
end
Expand All @@ -42,13 +42,13 @@ def initialize(key, encoding = :raw)
# @return [Boolean] was the signature authentic?
def verify(message, signature, signature_encoding = :raw)
signature = Encoder[signature_encoding].decode(signature)
Util.check_length(signature, NaCl::SIGNATUREBYTES, "signature")
Util.check_length(signature, signature_bytes, "signature")

sig_and_msg = signature + message
buffer = Util.zeros(sig_and_msg.bytesize)
buffer_len = Util.zeros(FFI::Type::LONG_LONG.size)

NaCl.crypto_sign_open(buffer, buffer_len, sig_and_msg, sig_and_msg.bytesize, @key)
NaCl.crypto_sign_ed25519_open(buffer, buffer_len, sig_and_msg, sig_and_msg.bytesize, @key)
end

# "Dangerous" (but probably safer) verify that raises an exception if a
Expand All @@ -72,5 +72,25 @@ def verify!(message, signature, signature_encoding = :raw)
#
# @return [String] raw key as bytes
def to_bytes; @key; end

# The crypto primitive the VerifyKey class uses for signatures
#
# @return [Symbol] The primitive
def self.primitive; :ed25519; end

# The crypto primitive this VerifyKey class uses for signatures
#
# @return [Symbol] The primitive
def primitive; self.class.primitive; end

# The size of signatures verified by the VerifyKey class
#
# @return [Integer] The number of bytes in a signature
def self.signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end

# The size of signatures verified by the VerifyKey instance
#
# @return [Integer] The number of bytes in a signature
def signature_bytes; NaCl::ED25519_SIGNATUREBYTES; end
end
end
Loading

0 comments on commit f189da2

Please sign in to comment.