Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
310 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.