From df977f18e831f4a9bd23e59880fb27a25144a24c Mon Sep 17 00:00:00 2001 From: Didactic Drunk <1479616+didactic-drunk@users.noreply.github.com> Date: Mon, 14 Jun 2021 12:07:31 -0700 Subject: [PATCH] Add Crypto::Secret::Stateless --- src/crypto-secret/not.cr | 4 ++- src/crypto-secret/secret.cr | 55 +++++++++++++--------------------- src/crypto-secret/stateless.cr | 54 +++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 35 deletions(-) create mode 100644 src/crypto-secret/stateless.cr diff --git a/src/crypto-secret/not.cr b/src/crypto-secret/not.cr index 3e7be60..185f278 100644 --- a/src/crypto-secret/not.cr +++ b/src/crypto-secret/not.cr @@ -1,10 +1,12 @@ +require "./stateless" + # A not very secret secret # # Not locked in memory # Not access protected # No guard pages struct Crypto::Secret::Not - include Crypto::Secret + include Crypto::Secret::Stateless def self.new(size) new Bytes.new(size) diff --git a/src/crypto-secret/secret.cr b/src/crypto-secret/secret.cr index 00e4f61..dfc7371 100644 --- a/src/crypto-secret/secret.cr +++ b/src/crypto-secret/secret.cr @@ -1,13 +1,12 @@ require "crypto/subtle" lib LibC - fun explicit_bzero(Void*, LibC::SizeT) : Int + fun explicit_bzero(Void*, LibC::SizeT) : Void end struct Slice(T) def wipe - r = LibC.explicit_bzero slice.to_unsafe, slice.bytesize - raise RunTimeError.from_errno("explicit_bzero") if r != 0 + LibC.explicit_bzero to_unsafe, bytesize end end @@ -21,41 +20,21 @@ module Crypto::Secret class Error < Exception class KeyWiped < Error end - end - def readwrite - end + class InvalidStateTransition < Error + end - # Yields a Slice that is readable and writable - # - # `slice` is only available within the block - # - # Not thread safe - def readwrite - to_slice do |slice| - yield slice + # Check RLIMIT_MEMLOCK if you receive this + class OutOfMemory < Error end end - def readonly - end - - # Yields a Slice that is readable possibly writable depending on the prior protection level and underlying implementation - # Don't write to it - # - # Not thread safe - def readonly - to_slice do |slice| - yield slice - end - end - - def noaccess - end - - # Not thread safe - def noaccess - yield + enum State + Cloning + Wiped + Noaccess + Readonly + Readwrite end # For debugging. @@ -66,7 +45,7 @@ module Crypto::Secret def wipe readwrite do |slice| - slice.wipe + wipe_impl slice end end @@ -105,6 +84,10 @@ module Crypto::Secret io << self.class.to_s << "(***SECRET***)" end + abstract def readwrite + abstract def readonly + abstract def noaccess + abstract def to_slice(& : Bytes -> Nil) abstract def bytesize : Int32 @@ -119,4 +102,8 @@ module Crypto::Secret {{object.id}}.bytesize end end + + def wipe_impl(slice : Bytes) : Nil + slice.wipe + end end diff --git a/src/crypto-secret/stateless.cr b/src/crypto-secret/stateless.cr new file mode 100644 index 0000000..9061830 --- /dev/null +++ b/src/crypto-secret/stateless.cr @@ -0,0 +1,54 @@ +require "./secret" + +# Provides a 0 overhead implementation of [#readwrite, #readonly, #noaccess, #reset] with no protection +# +# Data is still erased when out of scope +module Crypto::Secret::Stateless + include Crypto::Secret + + # Not thread safe + def readwrite + end + + # Yields a Slice that is readable and writable + # + # `slice` is only available within the block + # + # Not thread safe + def readwrite + to_slice do |slice| + yield slice + end + end + + # Not thread safe + def readonly + end + + # Yields a Slice that is readable possibly writable depending on the prior protection level and underlying implementation + # Don't write to it + # + # Not thread safe + def readonly + to_slice do |slice| + yield slice + end + end + + # Not thread safe + def noaccess + end + + # Not thread safe + def noaccess + yield + end + + # Not thread safe + def reset + end + + def finalize + wipe + end +end