Skip to content

Commit

Permalink
Merge 1dba4a9 into b62f035
Browse files Browse the repository at this point in the history
  • Loading branch information
robbat2 committed Dec 31, 2017
2 parents b62f035 + 1dba4a9 commit fa5745d
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 39 deletions.
4 changes: 4 additions & 0 deletions lib/rbnacl.rb
Expand Up @@ -46,6 +46,9 @@ class BadAuthenticatorError < CryptoError; end
require "rbnacl/boxes/curve25519xsalsa20poly1305/private_key"
require "rbnacl/boxes/curve25519xsalsa20poly1305/public_key"

# Sealed boxes
require "rbnacl/boxes/sealed"

# Secret Key Encryption (SecretBox): XSalsa20Poly1305
require "rbnacl/secret_boxes/xsalsa20poly1305"

Expand Down Expand Up @@ -88,6 +91,7 @@ class BadAuthenticatorError < CryptoError; end
Box = Boxes::Curve25519XSalsa20Poly1305
PrivateKey = Boxes::Curve25519XSalsa20Poly1305::PrivateKey
PublicKey = Boxes::Curve25519XSalsa20Poly1305::PublicKey
SealedBox = Boxes::Sealed
SecretBox = SecretBoxes::XSalsa20Poly1305
SigningKey = Signatures::Ed25519::SigningKey
VerifyKey = Signatures::Ed25519::VerifyKey
Expand Down
6 changes: 3 additions & 3 deletions lib/rbnacl/aead/chacha20poly1305_ietf.rb
Expand Up @@ -11,9 +11,9 @@ class ChaCha20Poly1305IETF < RbNaCl::AEAD::Base
sodium_type :aead
sodium_primitive :chacha20poly1305_ietf

sodium_constant :KEYBYTES
sodium_constant :NPUBBYTES
sodium_constant :ABYTES
sodium_type_primitive_constant :KEYBYTES
sodium_type_primitive_constant :NPUBBYTES
sodium_type_primitive_constant :ABYTES

sodium_function :aead_chacha20poly1305_ietf_encrypt,
:crypto_aead_chacha20poly1305_ietf_encrypt,
Expand Down
6 changes: 3 additions & 3 deletions lib/rbnacl/aead/chacha20poly1305_legacy.rb
Expand Up @@ -10,9 +10,9 @@ class ChaCha20Poly1305Legacy < RbNaCl::AEAD::Base

sodium_type :aead
sodium_primitive :chacha20poly1305
sodium_constant :KEYBYTES
sodium_constant :NPUBBYTES
sodium_constant :ABYTES
sodium_type_primitive_constant :KEYBYTES
sodium_type_primitive_constant :NPUBBYTES
sodium_type_primitive_constant :ABYTES

sodium_function :aead_chacha20poly1305_encrypt,
:crypto_aead_chacha20poly1305_encrypt,
Expand Down
190 changes: 190 additions & 0 deletions lib/rbnacl/boxes/sealed.rb
@@ -0,0 +1,190 @@
# encoding: binary
# frozen_string_literal: true

module RbNaCl
module Boxes
# The Box class boxes and unboxes messages between a pair of keys
#
# This class uses the given public and secret keys to derive a shared key,
# which is used with the nonce given to encrypt the given messages and
# decrypt the given ciphertexts. The same shared key will generated from
# both pairing of keys, so given two keypairs belonging to alice (pkalice,
# skalice) and bob(pkbob, skbob), the key derived from (pkalice, skbob) with
# equal that from (pkbob, skalice). This is how the system works:
#
# @example
# # On bob's system
# bobkey = RbNaCl::PrivateKey.generate
# #=> #<RbNaCl::PrivateKey ...>
#
# # send bobkey.public_key to alice
# # receive alice's public key, alicepk
# # NB: This is actually the hard part of the system. How to do it securely
# # is left as an exercise to for the reader.
# alice_pubkey = "..."
#
# # make a box
# alicebob_box = RbNaCl::Box.new(alice_pubkey, bobkey)
# #=> #<RbNaCl::Box ...>
#
# # encrypt a message to alice
# cipher_text = alicebob_box.box("A bad example of a nonce", "Hello, Alice!")
# #=> "..." # a string of bytes, 29 bytes long
#
# # send ["A bad example of a nonce", cipher_text] to alice
# # note that nonces don't have to be secret
# # receive [nonce, cipher_text_to_bob] from alice
#
# # decrypt the reply
# # Alice has been a little more sensible than bob, and has a random nonce
# # that is too fiddly to type here. But there are other choices than just
# # random
# plain_text = alicebob_box.open(nonce, cipher_text_to_bob)
# #=> "Hey there, Bob!"
#
# # we have a new message!
# # But Eve has tampered with this message, by flipping some bytes around!
# # [nonce2, cipher_text_to_bob_honest_love_eve]
# alicebob_box.open(nonce2, cipher_text_to_bob_honest_love_eve)
#
# # BOOM!
# # Bob gets a RbNaCl::CryptoError to deal with!
#
# It is VITALLY important that the nonce is a nonce, i.e. it is a number used
# only once for any given pair of keys. If you fail to do this, you
# compromise the privacy of the the messages encrypted. Also, bear in mind
# the property mentioned just above. Give your nonces a different prefix, or
# have one side use an odd counter and one an even counter. Just make sure
# they are different.
#
# The ciphertexts generated by this class include a 16-byte authenticator which
# is checked as part of the decryption. An invalid authenticator will cause
# the unbox function to raise. The authenticator is not a signature. Once
# you've looked in the box, you've demonstrated the ability to create
# arbitrary valid messages, so messages you send are repudiable. For
# non-repudiable messages, sign them before or after encryption.
class Sealed
extend Sodium

sodium_type :box
sodium_primitive :curve25519xsalsa20poly1305
sodium_type_constant :SEALBYTES

sodium_function :box_seal,
:crypto_box_seal,
%i[pointer pointer ulong_long pointer]

sodium_function :box_seal_open,
:crypto_box_seal_open,
%i[pointer pointer ulong_long pointer pointer]

# WARNING: you should strongly prefer the from_private_key/from_public_key class methods.
#
# Create a new Sealed Box
#
# Sets up the Box for deriving the shared key and encrypting and
# decrypting messages.
#
# @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to
# @param private_key [String,RbNaCl::PrivateKey] The private key to decrypt with
#
# @raise [RbNaCl::LengthError] on invalid keys
#
# @return [RbNaCl::SealedBox] The new Box, ready to use
private
def initialize(public_key, private_key = nil)
unless private_key.nil?
@private_key = private_key.is_a?(PrivateKey) ? private_key : PrivateKey.new(private_key)
raise IncorrectPrimitiveError unless @private_key.primitive == primitive
if public_key.nil?
public_key = @private_key.public_key
end
end

@public_key = public_key.is_a?(PublicKey) ? public_key : PublicKey.new(public_key)
raise IncorrectPrimitiveError unless @public_key.primitive == primitive
end

public
# Create a new Sealed Box for encrypting
#
# Sets up the Box for encryoption of new messages.
#
# @param private_key [String,RbNaCl::PrivateKey] The private key to decrypt with
#
# @raise [RbNaCl::LengthError] on invalid keys
#
# @return [RbNaCl::SealedBox] The new Box, ready to use
def self.from_private_key(private_key)
new(nil, private_key)
end

# Create a new Sealed Box for decrypting
#
# Sets up the Box for decrytoption of new messages.
#
# @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to
#
# @raise [RbNaCl::LengthError] on invalid keys
#
# @return [RbNaCl::SealedBox] The new Box, ready to use
def self.from_public_key(public_key)
new(public_key, nil)
end

# Encrypts a message
#
# TODO
#
# @param message [String] The message to be encrypted.
#
# @raise [RbNaCl::CryptoError] If the encrytion fails.
#
# @return [String] The ciphertext (BINARY encoded)
def box(message)
# No padding needed.
msg = message # variable name to match other RbNaCl code.
# ensure enough space in result
ct = Util.zeros(msg.bytesize + SEALBYTES)

success = self.class.box_seal(ct, msg, msg.bytesize, @public_key.to_s)
raise CryptoError, "Encryption failed" unless success

ct
end
alias encrypt box

# Decrypts a ciphertext
#
# TODO
#
# @param ciphertext [String] The message to be decrypted.
#
# @raise [RbNaCl::CryptoError] If no private key is available.
# @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated.
#
# @return [String] The decrypted message (BINARY encoded)
def open(ciphertext)
raise CryptoError, "Decryption failed. No private key." unless @private_key
ct = ciphertext
message = Util.zeros(ct.bytesize - SEALBYTES)

success = self.class.box_seal_open(message, ct, ct.bytesize, @public_key.to_s, @private_key.to_s)
raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success

message
end
alias decrypt open

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

private

end
end
end
12 changes: 6 additions & 6 deletions lib/rbnacl/hash/blake2b.rb
Expand Up @@ -17,12 +17,12 @@ class Blake2b

sodium_type :generichash
sodium_primitive :blake2b
sodium_constant :BYTES_MIN
sodium_constant :BYTES_MAX
sodium_constant :KEYBYTES_MIN
sodium_constant :KEYBYTES_MAX
sodium_constant :SALTBYTES
sodium_constant :PERSONALBYTES
sodium_type_primitive_constant :BYTES_MIN
sodium_type_primitive_constant :BYTES_MAX
sodium_type_primitive_constant :KEYBYTES_MIN
sodium_type_primitive_constant :KEYBYTES_MAX
sodium_type_primitive_constant :SALTBYTES
sodium_type_primitive_constant :PERSONALBYTES

sodium_function :generichash_blake2b,
:crypto_generichash_blake2b_salt_personal,
Expand Down
2 changes: 1 addition & 1 deletion lib/rbnacl/hash/sha256.rb
Expand Up @@ -8,7 +8,7 @@ module SHA256
extend Sodium
sodium_type :hash
sodium_primitive :sha256
sodium_constant :BYTES
sodium_type_primitive_constant :BYTES
sodium_function :hash_sha256,
:crypto_hash_sha256,
%i[pointer pointer ulong_long]
Expand Down
2 changes: 1 addition & 1 deletion lib/rbnacl/hash/sha512.rb
Expand Up @@ -8,7 +8,7 @@ module SHA512
extend Sodium
sodium_type :hash
sodium_primitive :sha512
sodium_constant :BYTES
sodium_type_primitive_constant :BYTES
sodium_function :hash_sha512,
:crypto_hash_sha512,
%i[pointer pointer ulong_long]
Expand Down
4 changes: 2 additions & 2 deletions lib/rbnacl/hmac/sha256.rb
Expand Up @@ -19,8 +19,8 @@ class SHA256 < Auth

sodium_type :auth
sodium_primitive :hmacsha256
sodium_constant :BYTES
sodium_constant :KEYBYTES
sodium_type_primitive_constant :BYTES
sodium_type_primitive_constant :KEYBYTES

sodium_function :auth_hmacsha256,
:crypto_auth_hmacsha256,
Expand Down
4 changes: 2 additions & 2 deletions lib/rbnacl/hmac/sha512.rb
Expand Up @@ -19,8 +19,8 @@ class SHA512 < Auth

sodium_type :auth
sodium_primitive :hmacsha512
sodium_constant :BYTES
sodium_constant :KEYBYTES
sodium_type_primitive_constant :BYTES
sodium_type_primitive_constant :KEYBYTES

sodium_function :auth_hmacsha512,
:crypto_auth_hmacsha512,
Expand Down
4 changes: 2 additions & 2 deletions lib/rbnacl/hmac/sha512256.rb
Expand Up @@ -19,8 +19,8 @@ class SHA512256 < Auth

sodium_type :auth
sodium_primitive :hmacsha512256
sodium_constant :BYTES
sodium_constant :KEYBYTES
sodium_type_primitive_constant :BYTES
sodium_type_primitive_constant :KEYBYTES

sodium_function :auth_hmacsha512256,
:crypto_auth_hmacsha512256,
Expand Down
4 changes: 2 additions & 2 deletions lib/rbnacl/one_time_auths/poly1305.rb
Expand Up @@ -24,8 +24,8 @@ class Poly1305 < Auth

sodium_type :onetimeauth
sodium_primitive :poly1305
sodium_constant :BYTES
sodium_constant :KEYBYTES
sodium_type_primitive_constant :BYTES
sodium_type_primitive_constant :KEYBYTES

sodium_function :onetimeauth_poly1305,
:crypto_onetimeauth_poly1305,
Expand Down
18 changes: 9 additions & 9 deletions lib/rbnacl/password_hash/argon2.rb
Expand Up @@ -15,15 +15,15 @@ class Argon2
sodium_type :pwhash
sodium_primitive :argon2i

sodium_constant :ALG_ARGON2I13
sodium_constant :SALTBYTES
sodium_constant :STRBYTES
sodium_constant :OPSLIMIT_INTERACTIVE # 4
sodium_constant :MEMLIMIT_INTERACTIVE # 2 ** 25 (32mb)
sodium_constant :OPSLIMIT_MODERATE # 6
sodium_constant :MEMLIMIT_MODERATE # 2 ** 27 (128mb)
sodium_constant :OPSLIMIT_SENSITIVE # 8
sodium_constant :MEMLIMIT_SENSITIVE # 2 ** 29 (512mb)
sodium_type_primitive_constant :ALG_ARGON2I13
sodium_type_primitive_constant :SALTBYTES
sodium_type_primitive_constant :STRBYTES
sodium_type_primitive_constant :OPSLIMIT_INTERACTIVE # 4
sodium_type_primitive_constant :MEMLIMIT_INTERACTIVE # 2 ** 25 (32mb)
sodium_type_primitive_constant :OPSLIMIT_MODERATE # 6
sodium_type_primitive_constant :MEMLIMIT_MODERATE # 2 ** 27 (128mb)
sodium_type_primitive_constant :OPSLIMIT_SENSITIVE # 8
sodium_type_primitive_constant :MEMLIMIT_SENSITIVE # 2 ** 29 (512mb)

ARGON2_MIN_OUTLEN = 16
ARGON2_MAX_OUTLEN = 0xFFFFFFFF
Expand Down
2 changes: 1 addition & 1 deletion lib/rbnacl/password_hash/scrypt.rb
Expand Up @@ -22,7 +22,7 @@ class SCrypt
sodium_type :pwhash
sodium_primitive :scryptsalsa208sha256

sodium_constant :SALTBYTES
sodium_type_primitive_constant :SALTBYTES

sodium_function :scrypt,
:crypto_pwhash_scryptsalsa208sha256,
Expand Down
8 changes: 4 additions & 4 deletions lib/rbnacl/secret_boxes/xsalsa20poly1305.rb
Expand Up @@ -24,10 +24,10 @@ class XSalsa20Poly1305

sodium_type :secretbox
sodium_primitive :xsalsa20poly1305
sodium_constant :KEYBYTES
sodium_constant :NONCEBYTES
sodium_constant :ZEROBYTES
sodium_constant :BOXZEROBYTES
sodium_type_primitive_constant :KEYBYTES
sodium_type_primitive_constant :NONCEBYTES
sodium_type_primitive_constant :ZEROBYTES
sodium_type_primitive_constant :BOXZEROBYTES

sodium_function :secretbox_xsalsa20poly1305,
:crypto_secretbox_xsalsa20poly1305,
Expand Down
20 changes: 17 additions & 3 deletions lib/rbnacl/sodium.rb
Expand Up @@ -29,10 +29,14 @@ def primitive
sodium_primitive
end

def sodium_constant(constant, name = constant)
def sodium_type_primitive_constant(constant, name = constant)
fn = "crypto_#{sodium_type}_#{sodium_primitive}_#{constant.to_s.downcase}"
attach_function fn, [], :size_t
const_set(name, public_send(fn))
_generic_constant(fn, name)
end

def sodium_type_constant(constant, name = constant)
fn = "crypto_#{sodium_type}_#{constant.to_s.downcase}"
_generic_constant(fn, name)
end

def sodium_function(name, function, arguments)
Expand All @@ -53,5 +57,15 @@ def self.#{name}(*args)
end
RUBY
end

# this alias exists to ensure we have a stable API
# remove for 6.0
alias sodium_constant sodium_type_primitive_constant

private
def _generic_constant(fn, name)
attach_function fn, [], :size_t
const_set(name, public_send(fn))
end
end
end

0 comments on commit fa5745d

Please sign in to comment.