Add Crypto::Secret::Guarded

Uses mmap with guard pages

New SecurityLevel: :strong

Adjust security levels <=> secret class mapping
This commit is contained in:
Didactic Drunk 2022-05-22 18:12:01 -07:00
parent 1e60a35fd4
commit 49a999732e
4 changed files with 67 additions and 8 deletions

View File

@ -6,4 +6,9 @@ authors:
crystal: ">= 0.37"
dependencies:
mmap:
github: crystal-posix/mmap.cr
version: ">= 0.4.0"
license: MIT

View File

@ -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

View File

@ -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

View 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