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 "./spec_helper"
|
||||||
require "../src/crypto-secret/test"
|
require "../src/crypto-secret/test"
|
||||||
require "../src/crypto-secret/not"
|
require "../src/crypto-secret"
|
||||||
require "../src/crypto-secret/large"
|
#require "../src/crypto-secret/not"
|
||||||
require "../src/crypto-secret/key"
|
#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
|
||||||
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
|
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.
|
# 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 locked in memory
|
||||||
# * Not access protected
|
# * Not access protected
|
||||||
# * No guard pages
|
# * 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
|
extend ClassMethods
|
||||||
|
|
||||||
abstract class Base
|
def self.new(size : Int32)
|
||||||
|
raise NotImplementedError.new("workaround for lack of `abstract def self.new`")
|
||||||
end
|
end
|
||||||
|
|
||||||
REGISTERED = Hash(Symbol, Secret::Base.class).new
|
def self.for(secret : Crypto::Secret) : Crypto::Secret
|
||||||
# REGISTERED_USES = {} of Nil => Nil
|
secret
|
||||||
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 %}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
macro register_class(klass, load_path, *uses)
|
def self.for(use : Symbol, size : Int32) : Crypto::Secret
|
||||||
{% 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)
|
|
||||||
for(use).new(size)
|
for(use).new(size)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.for(use : Symbol) : Crypto::Secret.class
|
||||||
|
Config::USES[use]
|
||||||
|
end
|
||||||
|
|
||||||
# For debugging. Leaks the secret
|
# For debugging. Leaks the secret
|
||||||
#
|
#
|
||||||
# Returned String **not** tracked or wiped
|
# Returned String **not** tracked or wiped
|
||||||
@ -207,3 +190,4 @@ puts "key=klass"
|
|||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require "./config"
|
||||||
|
@ -31,7 +31,7 @@ module Crypto::Secret
|
|||||||
|
|
||||||
# Marks a region allocated as readable and writable
|
# Marks a region allocated as readable and writable
|
||||||
# WARNING: Not thread safe
|
# WARNING: Not thread safe
|
||||||
def readwrite : self
|
def readwrite : Secret
|
||||||
raise Error::KeyWiped.new if @state == State::Wiped
|
raise Error::KeyWiped.new if @state == State::Wiped
|
||||||
readwrite_impl
|
readwrite_impl
|
||||||
@state = State::Readwrite
|
@state = State::Readwrite
|
||||||
@ -50,7 +50,7 @@ module Crypto::Secret
|
|||||||
|
|
||||||
# Marks a region allocated using sodium_malloc() or sodium_allocarray() as read-only.
|
# Marks a region allocated using sodium_malloc() or sodium_allocarray() as read-only.
|
||||||
# WARNING: Not thread safe
|
# WARNING: Not thread safe
|
||||||
def readonly : self
|
def readonly : Secret
|
||||||
raise Error::KeyWiped.new if @state == State::Wiped
|
raise Error::KeyWiped.new if @state == State::Wiped
|
||||||
readonly_impl
|
readonly_impl
|
||||||
@state = State::Readonly
|
@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.
|
# Makes a region inaccessible. It cannot be read or written, but the data are preserved.
|
||||||
# WARNING: Not thread safe
|
# WARNING: Not thread safe
|
||||||
def noaccess : self
|
def noaccess : Secret
|
||||||
raise Error::KeyWiped.new if @state == State::Wiped
|
raise Error::KeyWiped.new if @state == State::Wiped
|
||||||
noaccess_impl
|
noaccess_impl
|
||||||
@state = State::Noaccess
|
@state = State::Noaccess
|
||||||
|
@ -2,7 +2,7 @@ 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 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
|
module Crypto::Secret::Stateless
|
||||||
include Crypto::Secret
|
include Crypto::Secret
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ module Crypto::Secret::Stateless
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Not thread safe
|
# Not thread safe
|
||||||
def readwrite : self
|
def readwrite : Secret
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ module Crypto::Secret::Stateless
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Not thread safe
|
# Not thread safe
|
||||||
def readonly : self
|
def readonly : Secret
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -42,12 +42,13 @@ module Crypto::Secret::Stateless
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Not thread safe
|
# Not thread safe
|
||||||
def noaccess : self
|
def noaccess : Secret
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Not thread safe
|
# Not thread safe
|
||||||
def reset
|
def reset : Secret
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize
|
def finalize
|
||||||
|
Loading…
Reference in New Issue
Block a user