I've been exploring the feasibility of using ML-DSA and it is mostly available.
Key generation, or importing a seed:
seed = "\x01" * 32 # Example seed
key = OpenSSL::PKey.generate_key("ML-DSA-44", "hexseed" => seed.unpack1("H*"))
Sign and verify, with a context:
sig = key.sign(nil, "data", "context-string" => "foo")
result = key.verify(nil, sig, "data", "context-string" => "foo")
Getting the public key and private key
public_key = key.raw_public_key
private_key = key.raw_private_key
However there is one thing that is missing: getting the seed. The only way I can see doing this today is to do a PKCS#8 export and decode it, and extract the seed. This required OpenSSL's conf to export with seeds by default (it does) however it doesn't mean it can absolutely be depended upon, and it makes it more difficult to do.
The seed is becoming the more common means for transporting an ML-DSA (and ML-KEM) private key. Seeds are smaller and have better security properties, so a number of protocols are using the seed to represent the private key, not the expanded private key. This is important for generated keys, not keys where the seed was imported.
The way to do this through OpenSSL's API surface is EVP_PKEY_get_octet_string_param. I suppose I would suggest something like get_octet_string_param on PKey. This would translate to EVP_PKEY_get_octet_string_param, if it is available.
That would result in a usage like:
pkey.get_octet_string_param("seed") # "seed" is OSSL_PKEY_PARAM_ML_DSA_SEED.
Adding this would give a fully functional ML-DSA API set, and allow fetching other octet-string parameters from the key in the future without any additional work.
I'm happy to do the work here, provided we feel this is the right approach.
I've been exploring the feasibility of using ML-DSA and it is mostly available.
Key generation, or importing a seed:
Sign and verify, with a context:
Getting the public key and private key
However there is one thing that is missing: getting the seed. The only way I can see doing this today is to do a PKCS#8 export and decode it, and extract the seed. This required OpenSSL's conf to export with seeds by default (it does) however it doesn't mean it can absolutely be depended upon, and it makes it more difficult to do.
The seed is becoming the more common means for transporting an ML-DSA (and ML-KEM) private key. Seeds are smaller and have better security properties, so a number of protocols are using the seed to represent the private key, not the expanded private key. This is important for generated keys, not keys where the seed was imported.
The way to do this through OpenSSL's API surface is
EVP_PKEY_get_octet_string_param. I suppose I would suggest something likeget_octet_string_paramon PKey. This would translate toEVP_PKEY_get_octet_string_param, if it is available.That would result in a usage like:
Adding this would give a fully functional ML-DSA API set, and allow fetching other octet-string parameters from the key in the future without any additional work.
I'm happy to do the work here, provided we feel this is the right approach.