Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose access to XSalsa20Poly1305 primitive
This is to start to fix #43 Explicitly expose access to the XSalsa20Poly1305 primitive from the library. The primitive class handles all of the input checking, and the encryption methods. At the moment, the code has been more or less just copied across. Eventually, it might make sense to factor this out into the SecretBox module. Also, it's possible that one or other of the method calls might return something other than a string, augmented with additional information and methods.
- Loading branch information
1 parent
9be368b
commit 04eb156
Showing
5 changed files
with
141 additions
and
21 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# encoding: binary | ||
module Crypto | ||
module NaCl | ||
module SecretBox | ||
# The XSalsa20Poly1305Box class boxes and unboxes messages | ||
# | ||
# This class uses the given secret key to encrypt and decrypt messages. | ||
# | ||
# 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 messages encrypted. 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 | ||
# repudiatable. For non-repudiatable messages, sign them before or after | ||
# encryption. | ||
# | ||
# * Encryption: XSalsa20, a fast stream cipher primitive | ||
# * Authentication: Poly1305, a fast one time authentication primitive | ||
# | ||
# **WARNING**: This class provides direct access to a low-level | ||
# cryptographic method. You should not use this class without good | ||
# reason and instead use the Crypto::SecretBox box class which will | ||
# always point to the best primitive the library provides bindings for. | ||
# It also provides a nicer interface, with e.g. encoding of the resulting | ||
# messages as base64. | ||
class XSalsa20Poly1305Box | ||
# Number of bytes for a secret key | ||
KEYBYTES = NaCl::SecretBox::XSALSA20_POLY1305_KEYBYTES | ||
# Number of bytes for a nonce | ||
NONCEBYTES = NaCl::SecretBox::XSALSA20_POLY1305_NONCEBYTES | ||
|
||
# Create a new SecretBox | ||
# | ||
# Sets up the Box with a secret key fro encrypting and decrypting messages. | ||
# | ||
# @param key [String] The key to encrypt and decrypt with | ||
# | ||
# @raise [Crypto::LengthError] on invalid keys | ||
# | ||
# @return [Crypto::SecretBox] The new Box, ready to use | ||
def initialize(key) | ||
@key = key | ||
Util.check_length(@key, KEYBYTES, "Secret key") | ||
end | ||
|
||
# Encrypts a message | ||
# | ||
# Encrypts the message with the given nonce to the key set up when | ||
# initializing the class. Make sure the nonce is unique for any given | ||
# key, or you might as well just send plain text. | ||
# | ||
# This function takes care of the padding required by the NaCL C API. | ||
# | ||
# @param nonce [String] A 24-byte string containing the nonce. | ||
# @param message [String] The message to be encrypted. | ||
# | ||
# @raise [Crypto::LengthError] If the nonce is not valid | ||
# | ||
# @return [String] The ciphertext without the nonce prepended (BINARY encoded) | ||
def box(nonce, message) | ||
Util.check_length(nonce, NONCEBYTES, "Nonce") | ||
msg = Util.prepend_zeros(NaCl::ZEROBYTES, message) | ||
ct = Util.zeros(msg.bytesize) | ||
|
||
NaCl.crypto_secretbox_xsalsa20poly1305(ct, msg, msg.bytesize, nonce, @key) || raise(CryptoError, "Encryption failed") | ||
Util.remove_zeros(NaCl::BOXZEROBYTES, ct) | ||
end | ||
alias encrypt box | ||
|
||
# Decrypts a ciphertext | ||
# | ||
# Decrypts the ciphertext with the given nonce using the key setup when | ||
# initializing the class. | ||
# | ||
# This function takes care of the padding required by the NaCL C API. | ||
# | ||
# @param nonce [String] A 24-byte string containing the nonce. | ||
# @param ciphertext [String] The message to be decrypted. | ||
# | ||
# @raise [Crypto::LengthError] If the nonce is not valid | ||
# @raise [Crypto::CryptoError] If the ciphertext cannot be authenticated. | ||
# | ||
# @return [String] The decrypted message (BINARY encoded) | ||
def open(nonce, ciphertext) | ||
Util.check_length(nonce, NONCEBYTES, "Nonce") | ||
ct = Util.prepend_zeros(NaCl::BOXZEROBYTES, ciphertext) | ||
message = Util.zeros(ct.bytesize) | ||
|
||
NaCl.crypto_secretbox_xsalsa20poly1305_open(message, ct, ct.bytesize, nonce, @key) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.") | ||
Util.remove_zeros(NaCl::ZEROBYTES, message) | ||
end | ||
alias decrypt open | ||
end | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
require 'spec_helper' | ||
|
||
describe Crypto::NaCl::SecretBox::XSalsa20Poly1305Box do | ||
|
||
let (:key) { hex2bytes(Crypto::TestVectors[:secret_key]) } | ||
|
||
context "new" do | ||
it "accepts strings" do | ||
expect { described_class.new(key) }.to_not raise_error(Exception) | ||
end | ||
|
||
it "raises on a nil key" do | ||
expect { described_class.new(nil) }.to raise_error(Crypto::LengthError, "Secret key was nil \(Expected #{Crypto::NaCl::SECRETKEYBYTES}\)") | ||
end | ||
|
||
it "raises on a short key" do | ||
expect { described_class.new("hello") }.to raise_error(Crypto::LengthError, "Secret key was 5 bytes \(Expected #{Crypto::NaCl::SECRETKEYBYTES}\)") | ||
end | ||
end | ||
|
||
include_examples "box" do | ||
let(:box) { described_class.new(key) } | ||
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