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**
```
class MySecret
class MySecret < Crypto::Secret
# Choose one
include Crypto::Secret::Stateless
include Crypto::Secret::Stateful
def initialize(size)
def initialize(size : Int32)
# allocate or reference storage
# optionally mlock
end
@ -209,7 +209,7 @@ class MySecret
# optionally reencrypt or signal HSM
end
def bytesize : Int32
def buffer_bytesize : Int32
# return the size
end

View File

@ -1,8 +1,6 @@
require "./spec_helper"
require "../src/crypto-secret/test"
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::Bidet

View File

@ -1,6 +1,6 @@
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.
#
# * Wipes on finalize but should not be relied on
@ -8,7 +8,7 @@ module Crypto::Secret
# * Not access protected
# * No guard pages
# * Hours of fun
class Bidet < Base
class Bidet < Secret
include Stateless
def self.new(size : Int32)
@ -20,6 +20,6 @@ module Crypto::Secret
end
delegate_to_slice @bytes
delegate_to_bytesize @bytes.bytesize
delegate_buffer_bytesize_to @bytes.bytesize
end
end

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
require "./stateless"
module Crypto::Secret
abstract class Crypto::Secret
# A not very secret `Secret`, but fast
#
# Suitable uses:
@ -12,7 +12,7 @@ module Crypto::Secret
# * Not access protected
# * No guard pages
# * No wiping
struct Not
class Not < Secret
include Stateless
def self.new(size : Int32)
@ -25,7 +25,7 @@ module Crypto::Secret
end
delegate_to_slice @bytes
delegate_to_bytesize @bytes.bytesize
delegate_buffer_bytesize_to @bytes.bytesize
def wipe
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))
@[Experimental]
module Crypto::Secret
abstract class Crypto::Secret
class Error < Exception
class KeyWiped < Error
end
@ -162,7 +162,11 @@ module Crypto::Secret
abstract def readonly(& : 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)
def to_slice(& : Bytes -> U) forall U
@ -170,8 +174,8 @@ module Crypto::Secret
end
end
macro delegate_to_bytesize(to object)
def bytesize : Int32
macro delegate_buffer_bytesize_to(to object)
def buffer_bytesize : Int32
{{object.id}}
end
end
@ -181,13 +185,4 @@ module Crypto::Secret
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"

View File

@ -1,6 +1,6 @@
require "./secret"
module Crypto::Secret
abstract class Crypto::Secret
# Development guide:
# 1. Create your initialize method and optionally allocate memory
# 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.
module Stateful
include Crypto::Secret
macro included
extend ClassMethods
end
@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
#
# 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
include Crypto::Secret
macro included
extend ClassMethods
end
# Not thread safe
def readwrite : Secret
self