ektrah / nsec

A modern and easy-to-use cryptographic library for .NET 8+ based on libsodium
https://nsec.rocks
MIT License
374 stars 52 forks source link

Method to determine key type if the key is a valid NSec key format #45

Closed sigaloid closed 3 years ago

sigaloid commented 3 years ago

Dealt with a bug for 3 days because of a single typo of an X25519 key being imported as an Ed25519 key. Would be nice to input a byte[40] and get the key type, if it's valid.

ektrah commented 3 years ago

Glad to hear that you caught that bug 😀

That sounds like it could be a useful addition. How would you use the method; could you provide some example code?

sigaloid commented 3 years ago
var key1 = Key.Create(KeyExchange.X25519 /*pretend we don't know this*/);
var key1Bytes = key1.Export(KeyFormat.NSecPrivateKey);
var importkey = Key.Import(NSec.Autodetect, key1Bytes, NSec.PrivateKey);

I found out I could simply inspect the bytes of a key and find out what type of key it was, that's what let me find the bug. I looked for documentation on the format of NSec.* keys but couldn't find any.

ektrah commented 3 years ago

Thanks a lot for the example! The implementation of the autodetect method would be roughly like this:

foreach (var algorithm in AllAlgorithms)
{
    if (algorithm.TryImport(algorithm, blob, KeyFormat.NSecPrivateKey, out var key))
    {
        return key;
    }
}
return null;

Is it worth adding that to NSec or would it be better to provide this e.g. as an example for using NSec? (I'm asking because I guess that users might want to customize the subset of algorithms and the format. Then the API could become quite complex.)

Documenting the key formats is indeed something that should be useful; I haven't got around to do it yet.

(Apologies if this is going a bit slow...)

ektrah commented 3 years ago

What about this?

 public static Key Import(
-    Algorithm algorithm,
+    Algorithm? algorithm,
     ReadOnlySpan<byte> blob,
     KeyBlobFormat format,
     in KeyCreationParameters creationParameters = default)

So it's the same method that already exists, except that, if algorithm is null, it would attempt to auto-detect algorithm.

ektrah commented 3 years ago

It seems this is not as simple as it seems: For foreach (var algorithm in AllAlgorithms) to work, NSec need to know the list of all algorithms. But some algorithms are in NSec.Experimental.

What we could do instead is this:

public static Key Import(
    Algorithm[] algorithms,
    ReadOnlySpan<byte> blob,
    KeyBlobFormat format,
    in KeyCreationParameters creationParameters = default)
{
    foreach (var algorithm in algorithms ?? Array.Empty<Algorithm>())
    {
        if (TryImport(algorithm, blob, format, out Key? key, in creationParameters) && key != null)
        {
            return key;
        }
    }

    throw Error.Format_InvalidBlob();
}

So it's a new function that takes an array of algorithms as input and then tries to import using each of them. Thoughts?

sigaloid commented 3 years ago

I was initially thinking of a function that would just inspect the beginning bytes and determine based on that (that's how I figured it out). It's a nitpicky edge case though, and if it would be too complicated to implement, that's okay with me.