sodium.cr/src/sodium/kdf.cr

56 lines
1.6 KiB
Crystal
Raw Normal View History

require "./lib_sodium"
require "./wipe"
module Sodium
2019-05-28 23:31:31 +02:00
class Kdf
include Wipe
KDF_KEY_SIZE = LibSodium.crypto_kdf_keybytes
KDF_CONTEXT_SIZE = LibSodium.crypto_kdf_contextbytes
@[Wipe::Var]
getter bytes : Bytes
2019-05-28 23:31:31 +02:00
delegate to_slice, to: @bytes
# Use an existing KDF key.
#
# WARNING: This class takes ownership of any key material passed to it.
# If you don't want this behavior pass a duplicate of the key to initialize().
2019-05-28 23:31:31 +02:00
def initialize(bytes : Bytes)
if bytes.bytesize != KDF_KEY_SIZE
raise ArgumentError.new("bytes must be #{KDF_KEY_SIZE}, got #{bytes.bytesize}")
2019-05-28 23:31:31 +02:00
end
@bytes = bytes
end
# Generate a new random KDF key.
#
# WARNING: This class takes ownership of any key material passed to it.
#
# Make sure to save kdf.bytes before kdf goes out of scope.
2019-05-28 23:31:31 +02:00
def initialize
@bytes = Random::Secure.random_bytes(KDF_KEY_SIZE)
2019-05-28 23:31:31 +02:00
end
# Derive a consistent subkey based on `context` and `subkey_id`.
#
# context and subkey don't need to be secret
# * context must be 8 bytes
# * subkey_size must be 16..64 bytes as of libsodium 1.0.17
#
def derive(context, subkey_id, subkey_size)
if context.bytesize != KDF_CONTEXT_SIZE
raise ArgumentError.new("context must be #{KDF_CONTEXT_SIZE}, got #{context.bytesize}")
2019-05-28 23:31:31 +02:00
end
subkey = Bytes.new subkey_size
if (ret = LibSodium.crypto_kdf_derive_from_key(subkey, subkey.bytesize, subkey_id, context, @bytes)) != 0
raise Sodium::Error.new("crypto_kdf_derive_from_key returned #{ret} (subkey size is probably out of range)")
2019-05-28 23:31:31 +02:00
end
subkey
end
end
end