Add Crypto::Secret::Guarded
Uses mmap with guard pages New SecurityLevel: :strong Adjust security levels <=> secret class mapping
This commit is contained in:
parent
1e60a35fd4
commit
49a999732e
@ -6,4 +6,9 @@ authors:
|
||||
|
||||
crystal: ">= 0.37"
|
||||
|
||||
dependencies:
|
||||
mmap:
|
||||
github: crystal-posix/mmap.cr
|
||||
version: ">= 0.4.0"
|
||||
|
||||
license: MIT
|
||||
|
@ -4,7 +4,7 @@ require "../src/crypto-secret"
|
||||
|
||||
test_secret_class Crypto::Secret::Not
|
||||
test_secret_class Crypto::Secret::Bidet
|
||||
# test_secret_class Crypto::Secret::Guarded
|
||||
test_secret_class Crypto::Secret::Guarded
|
||||
|
||||
describe Crypto::Secret do
|
||||
it ".for" do
|
||||
|
@ -1,10 +1,11 @@
|
||||
require "./not"
|
||||
require "./bidet"
|
||||
require "./guarded"
|
||||
|
||||
{% if @type.has_constant?("Sodium") %}
|
||||
CRYPTO_SECRET_KEY_CLASS = Sodium::SecureBuffer
|
||||
{% else %}
|
||||
CRYPTO_SECRET_KEY_CLASS = Crypto::Secret::Bidet
|
||||
CRYPTO_SECRET_KEY_CLASS = Crypto::Secret::Guarded
|
||||
{% end %}
|
||||
|
||||
module Crypto::Secret::Config
|
||||
@ -12,28 +13,34 @@ module Crypto::Secret::Config
|
||||
USES = Hash(Symbol, Secret.class).new
|
||||
|
||||
enum SecurityLevel
|
||||
# mlocks everything (including data)
|
||||
Paranoid
|
||||
# wipes everything
|
||||
Strong
|
||||
# balance between performance and wiping
|
||||
Default
|
||||
# performance
|
||||
Lax
|
||||
# None
|
||||
end
|
||||
|
||||
def self.setup(level : SecurityLevel = :default) : Nil
|
||||
register_use Not, :not
|
||||
register_use Not, :not, :public_key
|
||||
|
||||
case level
|
||||
in SecurityLevel::Paranoid
|
||||
register_use Bidet, :not, :public_key
|
||||
register_use Bidet, :not
|
||||
register_use Guarded, :public_key
|
||||
register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :secret_key, :data
|
||||
in SecurityLevel::Strong
|
||||
register_use Bidet, :not, :public_key
|
||||
register_use Crypto::Secret::Guarded, :data
|
||||
register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :secret_key
|
||||
in SecurityLevel::Default
|
||||
register_use Not, :public_key
|
||||
register_use Crypto::Secret::Bidet, :data
|
||||
register_use CRYPTO_SECRET_KEY_CLASS, :kgk, :secret_key
|
||||
in SecurityLevel::Lax
|
||||
register_use Not, :public_key
|
||||
register_use Bidet, :kgk, :secret_key, :data
|
||||
# in SecurityLevel::None
|
||||
# register_use Not, :kgk, :secret_key, :data
|
||||
end
|
||||
end
|
||||
|
||||
|
47
src/crypto-secret/guarded.cr
Normal file
47
src/crypto-secret/guarded.cr
Normal file
@ -0,0 +1,47 @@
|
||||
require "./stateful"
|
||||
require "mmap"
|
||||
|
||||
abstract class Crypto::Secret
|
||||
# * Wipes on finalize but should not be relied on
|
||||
# * Not locked in memory
|
||||
# * Access protected
|
||||
# * Guard pages
|
||||
# * Won't appear in core dumps (some platforms)
|
||||
class Guarded < Secret
|
||||
include Stateful
|
||||
|
||||
protected getter buffer_bytesize : Int32
|
||||
@dregion : Mmap::SubRegion
|
||||
@data : Mmap::SubRegion
|
||||
|
||||
def initialize(size : Int32)
|
||||
ps = Mmap::PAGE_SIZE
|
||||
pages = (size.to_f / ps).ceil + 2
|
||||
msize = pages * ps
|
||||
|
||||
@buffer_bytesize = size
|
||||
|
||||
@mmap = Mmap::Region.new(msize)
|
||||
@mmap[0, ps].guard_page
|
||||
@mmap[(pages - 1) * ps, ps].guard_page
|
||||
|
||||
@dregion = @mmap[ps, (pages - 2) * ps]
|
||||
@dregion.crypto_key
|
||||
@data = @dregion[0, size]
|
||||
end
|
||||
|
||||
protected def readwrite_impl : Nil
|
||||
@dregion.readwrite
|
||||
end
|
||||
|
||||
protected def readonly_impl : Nil
|
||||
@dregion.readonly
|
||||
end
|
||||
|
||||
protected def noaccess_impl : Nil
|
||||
@dregion.noaccess
|
||||
end
|
||||
|
||||
delegate_to_slice @data
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user