2019-06-29 01:17:09 +02:00
|
|
|
module Sodium
|
2019-05-28 23:31:31 +02:00
|
|
|
class Kdf
|
2019-06-30 02:21:00 +02:00
|
|
|
KDF_KEY_SIZE = LibSodium.crypto_kdf_keybytes
|
|
|
|
KDF_CONTEXT_SIZE = LibSodium.crypto_kdf_contextbytes
|
|
|
|
|
2019-05-28 23:31:31 +02:00
|
|
|
property bytes : Bytes
|
|
|
|
|
2019-06-28 02:35:31 +02:00
|
|
|
delegate to_slice, to: @bytes
|
|
|
|
|
2019-05-28 23:31:31 +02:00
|
|
|
def initialize(bytes : Bytes)
|
2019-06-30 02:21:00 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
def initialize
|
2019-06-30 02:21:00 +02:00
|
|
|
@bytes = Random::Secure.random_bytes(KDF_KEY_SIZE)
|
2019-05-28 23:31:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
# context must be 8 bytes
|
|
|
|
# subkey_size must be 16..64 bytes as of libsodium 1.0.17
|
2019-06-28 01:52:45 +02:00
|
|
|
def derive(context, subkey_id, subkey_size)
|
2019-06-30 02:21:00 +02:00
|
|
|
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
|
2019-06-29 01:17:09 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
def to_base64
|
|
|
|
Base64.encode(bytes)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.from_base64(encoded_key)
|
|
|
|
new(Base64.decode(encoded_key))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|