Add libsodium kdf.
parent
e82d4416b4
commit
a358929e62
|
@ -55,6 +55,15 @@ signature = Cox.sign_detached(message, signing_pair.secret)
|
|||
Cox.verify_detached(signature, message, signing_pair.public) # => true
|
||||
```
|
||||
|
||||
# Key derivation
|
||||
kdf = Cox::Kdf.new
|
||||
|
||||
# kdf.derive(8_byte_context, subkey_size, subkey_id)
|
||||
subkey1 = kdf.derive "context1", 16, 0
|
||||
subkey2 = kdf.derive "context1", 16, 1
|
||||
subkey3 = kdf.derive "context2", 32, 0
|
||||
subkey4 = kdf.derive "context2", 64, 1
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork it ( https://github.com/andrewhamon/cox/fork )
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
require "../spec_helper"
|
||||
|
||||
CONTEXT = "8_bytess"
|
||||
|
||||
describe Cox::Kdf do
|
||||
it "generates master key" do
|
||||
kdf1 = Cox::Kdf.new
|
||||
|
||||
# verify loading saved key
|
||||
kdf2 = Cox::Kdf.from_base64 kdf1.to_base64
|
||||
|
||||
# verify generated subkey's are the same after loading
|
||||
key1_s1 = kdf1.derive CONTEXT, 16, 0
|
||||
key2_s1 = kdf2.derive CONTEXT, 16, 0
|
||||
key1_s1.should eq key2_s1
|
||||
end
|
||||
|
||||
it "generates different keys" do
|
||||
kdf1 = Cox::Kdf.new
|
||||
subkey1 = kdf1.derive CONTEXT, 16, 0
|
||||
subkey2 = kdf1.derive CONTEXT, 16, 1
|
||||
subkey1.should_not eq subkey2
|
||||
end
|
||||
|
||||
# TODO: test exceptions
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
module Cox
|
||||
class Kdf
|
||||
property bytes : Bytes
|
||||
|
||||
def initialize(bytes : Bytes)
|
||||
if bytes.bytesize != LibSodium::KDF_KEY_BYTES
|
||||
raise ArgumentError.new("bytes must be #{LibSodium::KDF_KEY_BYTES}, got #{bytes.bytesize}")
|
||||
end
|
||||
|
||||
@bytes = bytes
|
||||
end
|
||||
|
||||
def initialize
|
||||
@bytes = Random::Secure.random_bytes(LibSodium::KDF_KEY_BYTES)
|
||||
end
|
||||
|
||||
# context must be 8 bytes
|
||||
# subkey_size must be 16..64 bytes as of libsodium 1.0.17
|
||||
def derive(context, subkey_size, subkey_id = 0)
|
||||
if context.bytesize != LibSodium::KDF_CONTEXT_BYTES
|
||||
raise ArgumentError.new("context must be #{LibSodium::KDF_CONTEXT_BYTES}, got #{context.bytesize}")
|
||||
end
|
||||
|
||||
subkey = Bytes.new subkey_size
|
||||
if (ret = LibSodium.crypto_kdf_derive_from_key(subkey, subkey.bytesize, subkey_id, context, @bytes)) != 0
|
||||
raise Cox::Error.new("crypto_kdf_derive_from_key returned #{ret} (subkey size is probably out of range)")
|
||||
end
|
||||
subkey
|
||||
end
|
||||
|
||||
def pointer
|
||||
bytes.to_unsafe
|
||||
end
|
||||
|
||||
def pointer(size)
|
||||
bytes.pointer(size)
|
||||
end
|
||||
|
||||
def to_base64
|
||||
Base64.encode(bytes)
|
||||
end
|
||||
|
||||
def self.from_base64(encoded_key)
|
||||
new(Base64.decode(encoded_key))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,6 +10,8 @@ module Cox
|
|||
fun crypto_sign_publickeybytes() : LibC::SizeT
|
||||
fun crypto_sign_secretkeybytes() : LibC::SizeT
|
||||
fun crypto_sign_bytes() : LibC::SizeT
|
||||
fun crypto_kdf_keybytes() : LibC::SizeT
|
||||
fun crypto_kdf_contextbytes() : LibC::SizeT
|
||||
|
||||
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||
|
@ -18,6 +20,8 @@ module Cox
|
|||
PUBLIC_SIGN_BYTES = crypto_sign_publickeybytes()
|
||||
SECRET_SIGN_BYTES = crypto_sign_secretkeybytes()
|
||||
SIGNATURE_BYTES = crypto_sign_bytes()
|
||||
KDF_KEY_BYTES = crypto_kdf_keybytes()
|
||||
KDF_CONTEXT_BYTES = crypto_kdf_contextbytes()
|
||||
|
||||
fun crypto_box_keypair(
|
||||
public_key_output : Pointer(LibC::UChar),
|
||||
|
@ -61,5 +65,14 @@ module Cox
|
|||
message_size : LibC::ULongLong,
|
||||
public_key : Pointer(LibC::UChar)
|
||||
) : LibC::Int
|
||||
|
||||
|
||||
fun crypto_kdf_derive_from_key(
|
||||
subkey : Pointer(LibC::UChar),
|
||||
subkey_len : LibC::SizeT,
|
||||
subkey_id : UInt64,
|
||||
ctx : Pointer(LibC::UChar),
|
||||
key : Pointer(LibC::UChar)
|
||||
) : LibC::Int
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue