diff --git a/spec/not_spec.cr b/spec/not_spec.cr index 5a9413b..37e79b5 100644 --- a/spec/not_spec.cr +++ b/spec/not_spec.cr @@ -8,11 +8,15 @@ describe Crypto::Secret::Not do key[1] = 1_u8 secret1 = Crypto::Secret::Not.new key.dup - secret1.to_slice.should eq key + secret1.to_slice { |s| s.should eq key } secret2 = Crypto::Secret::Not.new key.dup (secret1 == secret2).should be_true - (secret1 == secret2.to_slice).should be_true + secret1.to_slice do |s1| + secret2.to_slice do |s2| + (s1 == s2).should be_true + end + end end end diff --git a/src/crypto-secret/not.cr b/src/crypto-secret/not.cr index 5c2a342..16de597 100644 --- a/src/crypto-secret/not.cr +++ b/src/crypto-secret/not.cr @@ -13,4 +13,8 @@ struct Crypto::Secret::Not def to_slice : Bytes @bytes end + + + delegate_to_slice @bytes + delegate_to_bytesize @bytes end diff --git a/src/crypto-secret/secret.cr b/src/crypto-secret/secret.cr index 217f14f..6d4614f 100644 --- a/src/crypto-secret/secret.cr +++ b/src/crypto-secret/secret.cr @@ -4,59 +4,101 @@ require "crypto/subtle" # # **Only for direct use by cryptographic library authors** # -# For all other applications use a preexisting class that include `Crypto::Secret` +# For all other applications use a preexisting class that includes `Crypto::Secret` @[Experimental] module Crypto::Secret - abstract def to_slice : Bytes + class Error < Exception + class KeyWiped < Error + end + end def readwrite end + # Yields a Slice that is readable and writable + # + # `slice` is only available within the block + # + # Not thread safe def readwrite - yield + to_slice do |slice| + yield slice + 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 - yield + to_slice do |slice| + yield slice + end end def noaccess end + # Not thread safe def noaccess yield end + # For debugging. + # Returned String **not** tracked or wiped + def hexstring : String + readonly &.hexstring + end + def wipe # Todo: implement wiping. Needs crystal support end + # Secret is wiped after exiting the block def wipe yield ensure wipe end + def reset + end + def finalize wipe end # Timing safe memory compare - def ==(other : Secret): Bool - readonly do - other.readonly do - Crypto::Subtle.constant_time_compare to_slice, other.to_slice + def ==(other : Secret) : Bool + readonly do |s1| + other.readonly do |s2| + Crypto::Subtle.constant_time_compare s1, s2 end end end # Timing safe memory compare def ==(other : Bytes) : Bool - readonly do - Crypto::Subtle.constant_time_compare to_slice, other.to_slice + readonly do |s1| + Crypto::Subtle.constant_time_compare s1, other + end + end + + abstract def to_slice(& : Bytes -> Nil) + abstract def bytesize : Int32 + + macro delegate_to_slice(to object) + def to_slice(& : Bytes -> Nil) + yield {{object.id}}.to_slice + end + end + + macro delegate_to_bytesize(to object) + def bytesize : Int32 + {{object.id}}.bytesize end end end