Add Crypto::Config
Runtime configuration of which Secret class to use Remove Secret::Key, Secret::Large
This commit is contained in:
parent
7e91cac498
commit
bfbaacab4d
@ -1,10 +1,17 @@
|
||||
require "./spec_helper"
|
||||
require "../src/crypto-secret/test"
|
||||
require "../src/crypto-secret/not"
|
||||
require "../src/crypto-secret/large"
|
||||
require "../src/crypto-secret/key"
|
||||
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
|
||||
test_secret_class Crypto::Secret::Large
|
||||
test_secret_class Crypto::Secret::Key
|
||||
|
||||
describe Crypto::Secret do
|
||||
it ".for" do
|
||||
[:kgk, :key, :data, :not].each do |sym|
|
||||
secret = Crypto::Secret.for sym, 2
|
||||
secret.bytesize.should eq 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,6 +3,7 @@ require "./stateless"
|
||||
module 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
|
||||
# * Not locked in memory
|
||||
# * Not access protected
|
||||
# * No guard pages
|
||||
|
42
src/crypto-secret/config.cr
Normal file
42
src/crypto-secret/config.cr
Normal file
@ -0,0 +1,42 @@
|
||||
{% if @type.has_constant?("Sodium") %}
|
||||
CRYPTO_SECRET_KEY_CLASS = Sodium::SecureBuffer
|
||||
{% else %}
|
||||
CRYPTO_SECRET_KEY_CLASS = Crypto::Secret::Bidet
|
||||
{% end %}
|
||||
|
||||
module Crypto::Secret::Config
|
||||
# :nodoc:
|
||||
USES = Hash(Symbol, Secret.class).new
|
||||
|
||||
enum SecurityLevel
|
||||
Paranoid
|
||||
Default
|
||||
Lax
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
setup # Safe defaults
|
||||
|
||||
def self.register_use(klass, *uses) : Nil
|
||||
uses.each do |use|
|
||||
USES[use] = klass
|
||||
end
|
||||
end
|
||||
end
|
@ -1,16 +0,0 @@
|
||||
require "./bidet"
|
||||
|
||||
# Use this class for holding small amounts of sensitive data such as crypto keys
|
||||
#
|
||||
# Underlying implentation subject to change
|
||||
#
|
||||
# Uses `Sodium::SecureBuffer` If "sodium" is required before "crypto-secret"
|
||||
{% if @type.has_constant?("Sodium") %}
|
||||
class Crypto::Secret::Key < ::Sodium::SecureBuffer
|
||||
end
|
||||
{% else %}
|
||||
# TODO: mlock
|
||||
# TODO: mprotect
|
||||
class Crypto::Secret::Key < ::Crypto::Secret::Bidet
|
||||
end
|
||||
{% end %}
|
@ -1,13 +0,0 @@
|
||||
require "./bidet"
|
||||
|
||||
module Crypto::Secret
|
||||
# Use this class as a default when holding possibly large amounts of data that may stress mlock limits
|
||||
#
|
||||
# Suitable uses: holding decrypted data
|
||||
#
|
||||
# no mlock
|
||||
#
|
||||
# Implementation subject to change
|
||||
class Large < Bidet
|
||||
end
|
||||
end
|
@ -33,39 +33,22 @@ module Crypto::Secret
|
||||
|
||||
extend ClassMethods
|
||||
|
||||
abstract class Base
|
||||
def self.new(size : Int32)
|
||||
raise NotImplementedError.new("workaround for lack of `abstract def self.new`")
|
||||
end
|
||||
|
||||
REGISTERED = Hash(Symbol, Secret::Base.class).new
|
||||
# REGISTERED_USES = {} of Nil => Nil
|
||||
REGISTERED_USES = {} of Symbol => String
|
||||
# REGISTERED_LOAD_PATHS = {} of Nil => Nil
|
||||
REGISTERED_LOAD_PATHS = {} of String => String
|
||||
|
||||
macro register(klass, *args)
|
||||
p "{{ args.id}}"
|
||||
{% for arg in args %}
|
||||
{% REGISTERED_USES[arg] = klass %}
|
||||
{% end %}
|
||||
def self.for(secret : Crypto::Secret) : Crypto::Secret
|
||||
secret
|
||||
end
|
||||
|
||||
macro register_class(klass, load_path, *uses)
|
||||
{% REGISTERED_LOAD_PATHS[klass] = load_path %}
|
||||
register *uses
|
||||
end
|
||||
|
||||
register_class "Crypto::Secret::Bidet", "./bidet", :ksk, :key, :data
|
||||
# register_class "Crypto::Secret::Not", "./not"
|
||||
register "Crypto::Secret::Bidet", :ksk, :key, :data
|
||||
|
||||
def self.for(use : Symbol) : Crypto::Secret::Base.class
|
||||
REGISTERED[use]
|
||||
end
|
||||
|
||||
def self.for(use : Symbol, size : Int32)
|
||||
def self.for(use : Symbol, size : Int32) : Crypto::Secret
|
||||
for(use).new(size)
|
||||
end
|
||||
|
||||
def self.for(use : Symbol) : Crypto::Secret.class
|
||||
Config::USES[use]
|
||||
end
|
||||
|
||||
# For debugging. Leaks the secret
|
||||
#
|
||||
# Returned String **not** tracked or wiped
|
||||
@ -207,3 +190,4 @@ puts "key=klass"
|
||||
{% end %}
|
||||
end
|
||||
|
||||
require "./config"
|
||||
|
@ -31,7 +31,7 @@ module Crypto::Secret
|
||||
|
||||
# Marks a region allocated as readable and writable
|
||||
# WARNING: Not thread safe
|
||||
def readwrite : self
|
||||
def readwrite : Secret
|
||||
raise Error::KeyWiped.new if @state == State::Wiped
|
||||
readwrite_impl
|
||||
@state = State::Readwrite
|
||||
@ -50,7 +50,7 @@ module Crypto::Secret
|
||||
|
||||
# Marks a region allocated using sodium_malloc() or sodium_allocarray() as read-only.
|
||||
# WARNING: Not thread safe
|
||||
def readonly : self
|
||||
def readonly : Secret
|
||||
raise Error::KeyWiped.new if @state == State::Wiped
|
||||
readonly_impl
|
||||
@state = State::Readonly
|
||||
@ -59,7 +59,7 @@ module Crypto::Secret
|
||||
|
||||
# Makes a region inaccessible. It cannot be read or written, but the data are preserved.
|
||||
# WARNING: Not thread safe
|
||||
def noaccess : self
|
||||
def noaccess : Secret
|
||||
raise Error::KeyWiped.new if @state == State::Wiped
|
||||
noaccess_impl
|
||||
@state = State::Noaccess
|
||||
|
@ -2,7 +2,7 @@ require "./secret"
|
||||
|
||||
# Provides a 0 overhead implementation of [#readwrite, #readonly, #noaccess, #reset] with no protection
|
||||
#
|
||||
# Data is still erased when out of scope
|
||||
# Data is erased when #wipe is out of scope, manual #wipe, or finalized except for `Not`
|
||||
module Crypto::Secret::Stateless
|
||||
include Crypto::Secret
|
||||
|
||||
@ -11,7 +11,7 @@ module Crypto::Secret::Stateless
|
||||
end
|
||||
|
||||
# Not thread safe
|
||||
def readwrite : self
|
||||
def readwrite : Secret
|
||||
self
|
||||
end
|
||||
|
||||
@ -27,7 +27,7 @@ module Crypto::Secret::Stateless
|
||||
end
|
||||
|
||||
# Not thread safe
|
||||
def readonly : self
|
||||
def readonly : Secret
|
||||
self
|
||||
end
|
||||
|
||||
@ -42,12 +42,13 @@ module Crypto::Secret::Stateless
|
||||
end
|
||||
|
||||
# Not thread safe
|
||||
def noaccess : self
|
||||
def noaccess : Secret
|
||||
self
|
||||
end
|
||||
|
||||
# Not thread safe
|
||||
def reset
|
||||
def reset : Secret
|
||||
self
|
||||
end
|
||||
|
||||
def finalize
|
||||
|
Loading…
Reference in New Issue
Block a user