Tool to simplify QKD migration by providing a (PQC) secret based ETSI-014 API.
Start the server:
echo "super_secret" > secret.txt
cargo r -- --secret-path secret.txt --addr 127.0.0.1:12345 &
cargo r -- --secret-path secret.txt --addr 127.0.0.1:12346 &Request a fresh key via curl:
curl -s -v http://localhost:12345/api/v1/keys/sae_ada/enc_keys?number=1 | jq
{
"keys": [
{
"key": "ZvmDBb77+1pMHvGHe0CXLAZyhgU6kE8PPwlR/bCo3dw=",
"key_ID": "36f0b2eb-066e-4151-97ae-26ff766806f1"
}
]
}The key_ID is now added to the internal registry and can't be requested again,
however a second instance with the same shared secred returns the key as
follows:
curl -s -v http://localhost:12346/api/v1/keys/sae_ada/dec_keys?key_ID=36f0b2eb-066e-4151-97ae-26ff766806f1 | jq
{
"keys": [
{
"key": "ZvmDBb77+1pMHvGHe0CXLAZyhgU6kE8PPwlR/bCo3dw=",
"key_ID": "36f0b2eb-066e-4151-97ae-26ff766806f1"
}
]
}Some details about the implementation.
Two API calls:
returns a new key_ID (UUIDv4) and key (base64([u8; 32]))
returns <key_ID> (UUIDv4) and key (base64([u8; 32]))
This is normally QKD based and fetched from a database, but could be generated based on a shared secret.
Combine the shared secret with a random UUID and use that as secret key.
secret = "very_secret"
key_id = uuid_v4()
new_key = hash(secret | key_id)
return { "key_ID": key_id, "key": new_key }
secret = "very_secret"
key_id = url.get_param("key_ID")
new_key = hash(secret | key_id)
return { "key_ID": key_id, "key": new_key }
What if the shared secret changes and is not 100% in sync between both instances? Different keys are generated without the consuming end device knowing about it.
Secondly a hash isn't recommended for this purpose, use a HKDF which offers different key lengths.
Add a hash of the secret to the key_ID and verify the ID's match, if not ask
the client to retry by sending a 404 Not Found.
secret = "very_secret"
secret_hash = hash(secret)
key_id = secret_hash[0..2] | uuid_v4()[2..16]
new_key = hkdf(secret | key_id)
return { "key_ID": key_id, "key": new_key }
secret = "very_secret"
secret_hash = hash(secret)
key_id = url.get_param("key_ID")
if key_id[0..2] != secret_hash[0..2]
return "key_not_found"
new_key = hkdf(secret | key_id)
return { "key_ID": key_id, "key": new_key }
- Add
/api/v1/statuscommand - Implement limit how many keys can be used per secret
- Implement
sizeparameter