More documentation
Implement #reset & #random with specs
This commit is contained in:
parent
363800bf1a
commit
8977222b44
@ -1,5 +1,6 @@
|
||||
module Crypto::Secret::ClassMethods
|
||||
# Copies `data` to the new Secret and **erases data**
|
||||
#
|
||||
# Returns a **readonly** Secret
|
||||
def move_from(data : Bytes)
|
||||
copy_from data
|
||||
@ -8,6 +9,7 @@ module Crypto::Secret::ClassMethods
|
||||
end
|
||||
|
||||
# Copies `data` to the new Secret
|
||||
#
|
||||
# Returns a **readonly** Secret
|
||||
def copy_from(data : Bytes)
|
||||
new(data.bytesize).tap do |obj|
|
||||
@ -20,9 +22,6 @@ module Crypto::Secret::ClassMethods
|
||||
# Returns a **readonly** random Secret
|
||||
def random(size)
|
||||
buf = new(size)
|
||||
buf.readwrite do |slice|
|
||||
Random::Secure.random_bytes slice
|
||||
end
|
||||
buf.readonly
|
||||
buf.random.readonly
|
||||
end
|
||||
end
|
||||
|
@ -15,7 +15,7 @@ lib LibC
|
||||
end
|
||||
|
||||
struct Slice(T)
|
||||
def wipe
|
||||
def wipe : Nil
|
||||
LibC.explicit_bzero to_unsafe, bytesize
|
||||
end
|
||||
end
|
||||
|
@ -35,12 +35,24 @@ module Crypto::Secret
|
||||
Readwrite
|
||||
end
|
||||
|
||||
extend ClassMethods
|
||||
|
||||
# For debugging.
|
||||
# Returned String **not** tracked or wiped
|
||||
def hexstring : String
|
||||
readonly &.hexstring
|
||||
end
|
||||
|
||||
def random : self
|
||||
readwrite do |slice|
|
||||
Random::Secure.random_bytes slice
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Zeroes data
|
||||
#
|
||||
# Secret is unavailable (readonly/readwrite may fail) until reset
|
||||
def wipe
|
||||
readwrite do |slice|
|
||||
wipe_impl slice
|
||||
@ -55,6 +67,7 @@ module Crypto::Secret
|
||||
end
|
||||
|
||||
def reset
|
||||
wipe
|
||||
end
|
||||
|
||||
def finalize
|
||||
@ -93,9 +106,13 @@ module Crypto::Secret
|
||||
end
|
||||
end
|
||||
|
||||
abstract def readwrite
|
||||
abstract def readonly
|
||||
abstract def noaccess
|
||||
|
||||
# Marks a region allocated using as read & write depending on implementation.
|
||||
abstract def readwrite : self
|
||||
# Marks a region allocated using as read-only depending on implementation.
|
||||
abstract def readonly : self
|
||||
# Makes a region allocated inaccessible depending on implementation. It cannot be read or written, but the data are preserved.
|
||||
abstract def noaccess : self
|
||||
|
||||
protected abstract def to_slice(& : Bytes -> Nil)
|
||||
abstract def bytesize : Int32
|
||||
|
@ -17,6 +17,7 @@ module Crypto::Secret
|
||||
end
|
||||
|
||||
@state = State::Readwrite
|
||||
@pre_wipe_state = State::Readwrite
|
||||
|
||||
# Temporarily make buffer readwrite within the block returning to the prior state on exit.
|
||||
# WARNING: Not thread safe unless this object is **readwrite**
|
||||
@ -65,6 +66,14 @@ module Crypto::Secret
|
||||
self
|
||||
end
|
||||
|
||||
def reset
|
||||
case @state
|
||||
when State::Wiped; set_state @pre_wipe_state
|
||||
else
|
||||
wipe_impl
|
||||
end
|
||||
end
|
||||
|
||||
# WARNING: Not thread safe
|
||||
# Kept public for .dup
|
||||
# :nodoc:
|
||||
@ -72,12 +81,10 @@ module Crypto::Secret
|
||||
return if @state == new_state
|
||||
|
||||
case new_state
|
||||
when State::Readwrite; readwrite
|
||||
when State::Readonly ; readonly
|
||||
when State::Noaccess ; noaccess
|
||||
when State::Wiped ; raise Error::InvalidStateTransition.new
|
||||
else
|
||||
raise "unknown state #{new_state}"
|
||||
in State::Readwrite; readwrite
|
||||
in State::Readonly ; readonly
|
||||
in State::Noaccess ; noaccess
|
||||
in State::Wiped ; raise Error::KeyWiped.new
|
||||
end
|
||||
end
|
||||
|
||||
@ -100,6 +107,7 @@ module Crypto::Secret
|
||||
# WARNING: Not thread safe
|
||||
def wipe
|
||||
return if @state == State::Wiped
|
||||
@pre_wipe_state = @state
|
||||
readwrite do |slice|
|
||||
wipe_impl slice
|
||||
end
|
||||
|
@ -76,5 +76,24 @@ macro test_secret_class(to sclass)
|
||||
|
||||
secret.inspect.should match /\(\*\*\*SECRET\*\*\*\)$/
|
||||
end
|
||||
|
||||
if sclass.is_a?(Crypto::Secret::Stateful)
|
||||
it "can't transition after #wipe except with #reset" do
|
||||
secret = sclass.new 1
|
||||
secret.wipe
|
||||
expect_raises Crypto::Secret::Error::KeyWiped do
|
||||
secret.readwrite
|
||||
end
|
||||
expect_raises Crypto::Secret::Error::KeyWiped do
|
||||
secret.readonly
|
||||
end
|
||||
expect_raises Crypto::Secret::Error::KeyWiped do
|
||||
secret.readnoaccess
|
||||
end
|
||||
|
||||
secret.reset
|
||||
secret.readonly
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user