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
|
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
|
## Contributing
|
||||||
|
|
||||||
1. Fork it ( https://github.com/andrewhamon/cox/fork )
|
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_publickeybytes() : LibC::SizeT
|
||||||
fun crypto_sign_secretkeybytes() : LibC::SizeT
|
fun crypto_sign_secretkeybytes() : LibC::SizeT
|
||||||
fun crypto_sign_bytes() : 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()
|
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||||
|
@ -18,6 +20,8 @@ module Cox
|
||||||
PUBLIC_SIGN_BYTES = crypto_sign_publickeybytes()
|
PUBLIC_SIGN_BYTES = crypto_sign_publickeybytes()
|
||||||
SECRET_SIGN_BYTES = crypto_sign_secretkeybytes()
|
SECRET_SIGN_BYTES = crypto_sign_secretkeybytes()
|
||||||
SIGNATURE_BYTES = crypto_sign_bytes()
|
SIGNATURE_BYTES = crypto_sign_bytes()
|
||||||
|
KDF_KEY_BYTES = crypto_kdf_keybytes()
|
||||||
|
KDF_CONTEXT_BYTES = crypto_kdf_contextbytes()
|
||||||
|
|
||||||
fun crypto_box_keypair(
|
fun crypto_box_keypair(
|
||||||
public_key_output : Pointer(LibC::UChar),
|
public_key_output : Pointer(LibC::UChar),
|
||||||
|
@ -61,5 +65,14 @@ module Cox
|
||||||
message_size : LibC::ULongLong,
|
message_size : LibC::ULongLong,
|
||||||
public_key : Pointer(LibC::UChar)
|
public_key : Pointer(LibC::UChar)
|
||||||
) : LibC::Int
|
) : 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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue