Switch Crypto::Secret from module to abstract class

This commit is contained in:
Didactic Drunk 2022-05-11 22:30:05 -07:00 committed by didactic-drunk
parent bfbaacab4d
commit 80a47aa966
10 changed files with 41 additions and 57 deletions

View File

@ -192,12 +192,12 @@ Each implementation may add additional protections
**Only intended for use by crypto library authors** **Only intended for use by crypto library authors**
``` ```
class MySecret class MySecret < Crypto::Secret
# Choose one # Choose one
include Crypto::Secret::Stateless include Crypto::Secret::Stateless
include Crypto::Secret::Stateful include Crypto::Secret::Stateful
def initialize(size) def initialize(size : Int32)
# allocate or reference storage # allocate or reference storage
# optionally mlock # optionally mlock
end end
@ -209,7 +209,7 @@ class MySecret
# optionally reencrypt or signal HSM # optionally reencrypt or signal HSM
end end
def bytesize : Int32 def buffer_bytesize : Int32
# return the size # return the size
end end

View File

@ -1,8 +1,6 @@
require "./spec_helper" require "./spec_helper"
require "../src/crypto-secret/test" require "../src/crypto-secret/test"
require "../src/crypto-secret" require "../src/crypto-secret"
#require "../src/crypto-secret/not"
#require "../src/crypto-secret/bidet"
test_secret_class Crypto::Secret::Not test_secret_class Crypto::Secret::Not
test_secret_class Crypto::Secret::Bidet test_secret_class Crypto::Secret::Bidet

View File

@ -1,6 +1,6 @@
require "./stateless" require "./stateless"
module Crypto::Secret abstract class Crypto::Secret
# Leaves less sh** around if you forget to wipe. A safer default for large secrets that may stress mlock limits or low confidentiality secrets. # Leaves less sh** around if you forget to wipe. A safer default for large secrets that may stress mlock limits or low confidentiality secrets.
# #
# * Wipes on finalize but should not be relied on # * Wipes on finalize but should not be relied on
@ -8,7 +8,7 @@ module Crypto::Secret
# * Not access protected # * Not access protected
# * No guard pages # * No guard pages
# * Hours of fun # * Hours of fun
class Bidet < Base class Bidet < Secret
include Stateless include Stateless
def self.new(size : Int32) def self.new(size : Int32)
@ -20,6 +20,6 @@ module Crypto::Secret
end end
delegate_to_slice @bytes delegate_to_slice @bytes
delegate_to_bytesize @bytes.bytesize delegate_buffer_bytesize_to @bytes.bytesize
end end
end end

View File

@ -1,3 +1,6 @@
require "./not"
require "./bidet"
{% if @type.has_constant?("Sodium") %} {% if @type.has_constant?("Sodium") %}
CRYPTO_SECRET_KEY_CLASS = Sodium::SecureBuffer CRYPTO_SECRET_KEY_CLASS = Sodium::SecureBuffer
{% else %} {% else %}
@ -12,23 +15,23 @@ module Crypto::Secret::Config
Paranoid Paranoid
Default Default
Lax Lax
None # None
end end
def self.setup(how : SecurityLevel = SecurityLevel::Default) : Nil def self.setup(level : SecurityLevel = SecurityLevel::Default) : Nil
case how register_use Not, :not
in SecurityLevel::Paranoid
register_use Bidet, :not case level
register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :key, :data in SecurityLevel::Paranoid
in SecurityLevel::Default register_use Bidet, :not
register_use Not, :not register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :key, :data
register_use Bidet, :data in SecurityLevel::Default
register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :key register_use Crypto::Secret::Bidet, :data
in SecurityLevel::Lax register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :key
register_use Not, :not in SecurityLevel::Lax
register_use Bidet, :kgk, :key, :data register_use Bidet, :kgk, :key, :data
in SecurityLevel::None # in SecurityLevel::None
register_use Not, :kgk, :key, :data, :not # register_use Not, :kgk, :key, :data
end end
end end

View File

@ -1,4 +1 @@
#require "./not"
require "./secret" require "./secret"
# require "./large"
# require "./key"

View File

@ -1,5 +1,5 @@
module Crypto module Crypto
module Secret abstract class Secret
module Stateless module Stateless
end end

View File

@ -1,6 +1,6 @@
require "./stateless" require "./stateless"
module Crypto::Secret abstract class Crypto::Secret
# A not very secret `Secret`, but fast # A not very secret `Secret`, but fast
# #
# Suitable uses: # Suitable uses:
@ -12,7 +12,7 @@ module Crypto::Secret
# * Not access protected # * Not access protected
# * No guard pages # * No guard pages
# * No wiping # * No wiping
struct Not class Not < Secret
include Stateless include Stateless
def self.new(size : Int32) def self.new(size : Int32)
@ -25,7 +25,7 @@ module Crypto::Secret
end end
delegate_to_slice @bytes delegate_to_slice @bytes
delegate_to_bytesize @bytes.bytesize delegate_buffer_bytesize_to @bytes.bytesize
def wipe def wipe
end end

View File

@ -10,7 +10,7 @@ require "./class_methods"
# #
# Other shards may provide additional `Secret` types ([sodium.cr](https://github.com/didactic-drunk/sodium.cr)) # Other shards may provide additional `Secret` types ([sodium.cr](https://github.com/didactic-drunk/sodium.cr))
@[Experimental] @[Experimental]
module Crypto::Secret abstract class Crypto::Secret
class Error < Exception class Error < Exception
class KeyWiped < Error class KeyWiped < Error
end end
@ -162,7 +162,11 @@ module Crypto::Secret
abstract def readonly(& : Bytes -> U) forall U abstract def readonly(& : Bytes -> U) forall U
protected abstract def to_slice(& : Bytes -> U) forall U protected abstract def to_slice(& : Bytes -> U) forall U
abstract def bytesize : Int32 abstract def buffer_bytesize : Int32
def bytesize : Int32
buffer_bytesize
end
macro delegate_to_slice(to object) macro delegate_to_slice(to object)
def to_slice(& : Bytes -> U) forall U def to_slice(& : Bytes -> U) forall U
@ -170,8 +174,8 @@ module Crypto::Secret
end end
end end
macro delegate_to_bytesize(to object) macro delegate_buffer_bytesize_to(to object)
def bytesize : Int32 def buffer_bytesize : Int32
{{object.id}} {{object.id}}
end end
end end
@ -181,13 +185,4 @@ module Crypto::Secret
end end
end end
macro finished
{% for key, klass in Crypto::Secret::REGISTERED_USES %}
#puts "{{key}}={{klass}}"
puts "key=klass"
require {{ Crypto::Secret::REGISTERED_LOAD_PATHS[klass] }}
Crypto::Secret::REGISTERED[:{{key.id}}] = {{klass.id}}
{% end %}
end
require "./config" require "./config"

View File

@ -1,6 +1,6 @@
require "./secret" require "./secret"
module Crypto::Secret abstract class Crypto::Secret
# Development guide: # Development guide:
# 1. Create your initialize method and optionally allocate memory # 1. Create your initialize method and optionally allocate memory
# 2. Create a finalize method to deallocate memory if necessary # 2. Create a finalize method to deallocate memory if necessary
@ -10,12 +10,6 @@ module Crypto::Secret
# #
# When state changes are required (such as using #noaccess) and the buffer is accessed from multiple threads wrap each #readonly/#readwrite block in a lock. # When state changes are required (such as using #noaccess) and the buffer is accessed from multiple threads wrap each #readonly/#readwrite block in a lock.
module Stateful module Stateful
include Crypto::Secret
macro included
extend ClassMethods
end
@state = State::Readwrite @state = State::Readwrite
@pre_wipe_state = State::Readwrite @pre_wipe_state = State::Readwrite

View File

@ -2,14 +2,11 @@ require "./secret"
# Provides a 0 overhead implementation of [#readwrite, #readonly, #noaccess, #reset] with no protection # Provides a 0 overhead implementation of [#readwrite, #readonly, #noaccess, #reset] with no protection
# #
# Data is erased when #wipe is out of scope, manual #wipe, or finalized except for `Not` # Data is erased when (except for `Crypto::Secret::Not`):
# * #wipe(&block) goes out of scope
# * manual #wipe
# * finalized
module Crypto::Secret::Stateless module Crypto::Secret::Stateless
include Crypto::Secret
macro included
extend ClassMethods
end
# Not thread safe # Not thread safe
def readwrite : Secret def readwrite : Secret
self self