Sodium::Nonce reuse detection.
parent
075c245011
commit
54a3cd8a8a
|
@ -99,6 +99,20 @@ describe Sodium::CryptoBox::SecretKey do
|
|||
String.new(decrypted).should eq(data)
|
||||
end
|
||||
|
||||
it "can't encrypt twice using the same nonce" do
|
||||
data = "Hello World!".to_slice
|
||||
|
||||
alice = Sodium::CryptoBox::SecretKey.new
|
||||
bob = Sodium::CryptoBox::SecretKey.new
|
||||
|
||||
alice.box bob.public_key do |box|
|
||||
encrypted, nonce = box.encrypt data
|
||||
expect_raises Sodium::Nonce::Error::Reused do
|
||||
box.encrypt data, nonce: nonce
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "PyNaCl combined test vectors" do
|
||||
combined_test_vectors.each do |vec|
|
||||
box_from_vec(vec) do |box1, box2, nonce, plaintext, ciphertext|
|
||||
|
|
|
@ -40,6 +40,17 @@ describe Sodium::SecretBox do
|
|||
end
|
||||
end
|
||||
|
||||
it "can't encrypt twice using the same nonce" do
|
||||
box = Sodium::SecretBox.new
|
||||
|
||||
message = "foobar"
|
||||
encrypted, nonce = box.encrypt message
|
||||
|
||||
expect_raises(Sodium::Nonce::Error::Reused) do
|
||||
box.encrypt message.to_slice, nonce: nonce
|
||||
end
|
||||
end
|
||||
|
||||
it "PyNaCl combined test vectors" do
|
||||
combined_test_vectors.each do |vec|
|
||||
box, nonce, plaintext, ciphertext = box_from_test_vector vec
|
||||
|
|
|
@ -35,7 +35,8 @@ module Sodium
|
|||
# Encrypts data and returns {ciphertext, nonce}
|
||||
#
|
||||
# Optionally supply a destination buffer.
|
||||
def encrypt(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.new) : {Bytes, Nonce}
|
||||
def encrypt(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.random) : {Bytes, Nonce}
|
||||
nonce.used!
|
||||
if LibSodium.crypto_box_easy_afternm(dst, src, src.bytesize, nonce.to_slice, @key.to_slice) != 0
|
||||
raise Error.new("crypto_box_easy")
|
||||
end
|
||||
|
|
|
@ -49,6 +49,8 @@ module Sodium
|
|||
fun sodium_memcmp(Pointer(LibC::UChar), Pointer(LibC::UChar), LibC::SizeT) : LibC::Int
|
||||
fun sodium_memzero(Pointer(LibC::UChar), LibC::SizeT) : Nil
|
||||
|
||||
fun sodium_increment(Pointer(LibC::UChar), LibC::SizeT) : Nil
|
||||
|
||||
fun sodium_malloc(LibC::SizeT) : Pointer(LibC::UChar)
|
||||
fun sodium_free(Pointer(LibC::UChar)) : Nil
|
||||
|
||||
|
|
|
@ -3,9 +3,16 @@ require "random/secure"
|
|||
|
||||
module Sodium
|
||||
class Nonce
|
||||
NONCE_SIZE = LibSodium::NONCE_SIZE
|
||||
class Error < Sodium::Error
|
||||
class Reused < Error
|
||||
end
|
||||
end
|
||||
|
||||
NONCE_SIZE = LibSodium::NONCE_SIZE.to_i
|
||||
|
||||
getter? used
|
||||
@used = false
|
||||
|
||||
getter bytes : Bytes
|
||||
delegate to_slice, to: @bytes
|
||||
|
||||
def initialize(@bytes : Bytes)
|
||||
|
@ -14,8 +21,22 @@ module Sodium
|
|||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
@bytes = Random::Secure.random_bytes(NONCE_SIZE)
|
||||
def self.random
|
||||
self.new Random::Secure.random_bytes(NONCE_SIZE)
|
||||
end
|
||||
|
||||
def self.zero
|
||||
self.new Bytes.new(NONCE_SIZE)
|
||||
end
|
||||
|
||||
def increment
|
||||
LibSodium.sodium_increment @bytes, @bytes.bytesize
|
||||
@used = false
|
||||
end
|
||||
|
||||
def used!
|
||||
raise Error::Reused.new("attempted nonce reuse") if @used
|
||||
@used = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,10 +54,11 @@ module Sodium
|
|||
# Encrypts data and returns {ciphertext, nonce}
|
||||
#
|
||||
# Optionally supply a destination buffer.
|
||||
def encrypt(src : Bytes, dst : Bytes = Bytes.new(src.bytesize + MAC_SIZE), nonce : Nonce = Nonce.new) : {Bytes, Nonce}
|
||||
def encrypt(src : Bytes, dst : Bytes = Bytes.new(src.bytesize + MAC_SIZE), nonce : Nonce = Nonce.random) : {Bytes, Nonce}
|
||||
if dst.bytesize != (src.bytesize + MAC_SIZE)
|
||||
raise ArgumentError.new("dst.bytesize must be src.bytesize + MAC_SIZE, got #{dst.bytesize}")
|
||||
end
|
||||
nonce.used!
|
||||
if LibSodium.crypto_secretbox_easy(dst, src, src.bytesize, nonce.to_slice, self.to_slice) != 0
|
||||
raise Sodium::Error.new("crypto_secretbox_easy")
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue