From c75a51c078421d884d9d896e0ce9347b5281256f Mon Sep 17 00:00:00 2001 From: Didactic Drunk <1479616+didactic-drunk@users.noreply.github.com> Date: Mon, 7 Jun 2021 11:05:13 -0700 Subject: [PATCH] Add Sodium::Nonce.random Improve Nonce used detection Improve Nonce documentation --- src/sodium/nonce.cr | 27 +++++++++++++++++++++------ src/sodium/sign/secret_key.cr | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/sodium/nonce.cr b/src/sodium/nonce.cr index 9ae45f1..11bb166 100644 --- a/src/sodium/nonce.cr +++ b/src/sodium/nonce.cr @@ -2,6 +2,8 @@ require "./lib_sodium" require "random/secure" module Sodium + # This class implements best effort nonce reuse detection **when multithreading is disabled** + # Race conditions may occur if using the same object in multiple Fibers with multithreading enabled. class Nonce class Error < Sodium::Error class Reused < Error @@ -13,7 +15,7 @@ module Sodium getter? used = false # Only use with single use keys. - property? reusable = false + getter reusable = false # Returns bytes delegate_to_slice to: @bytes @@ -26,22 +28,35 @@ module Sodium end end - def self.random - self.new Random::Secure.random_bytes(NONCE_SIZE) + def self.random(random_source = Random::Secure) + self.new random_source.random_bytes(NONCE_SIZE) end def self.zero self.new Bytes.new(NONCE_SIZE) end - def increment + def increment : Nil LibSodium.sodium_increment @bytes, @bytes.bytesize @used = false end - def used! + def random(random_source = Random::Secure) : Nil + random_source.random_bytes @bytes + @used = false + end + + def used! : Nil + return if @reusable raise Error::Reused.new("attempted nonce reuse") if @used - @used = true unless @reusable + @used = true + end + + def reusable=(val : Bool) : Bool + raise Error.new("trying to set reusable=true but already used") if val && @used + @reusable = val + @used = false if val + val end def dup diff --git a/src/sodium/sign/secret_key.cr b/src/sodium/sign/secret_key.cr index be33f8d..50ef624 100644 --- a/src/sodium/sign/secret_key.cr +++ b/src/sodium/sign/secret_key.cr @@ -40,7 +40,7 @@ module Sodium @sbuf = SecureBuffer.new bytes, erase: erase if pk = pkey - @public_key = PublicKey.new pkey + @public_key = PublicKey.new pk else @public_key = PublicKey.new if LibSodium.crypto_sign_ed25519_sk_to_pk(@public_key.to_slice, self.to_slice) != 0