- Simple: an easy-to-learn API with descriptive naming. Only one primitive for each task is provided when possible.
- Modern: the latest and greatest cryptographic primitives, such as (X)ChaCha20-Poly1305, BLAKE2b, Argon2id, X25519, and Ed25519.
Note that libsodium requires the Visual C++ Redistributable for Visual Studio 2015-2022 on Windows. This dependency is included in the .NET SDK.
If you want your program to be portable (e.g. self-contained), you can keep the relevant
vcruntime140.dllfile (available on GitHub) in the same directory as your executable.
- Descriptive naming: BLAKE2b, not GenericHash.
- Minimal parameters: no key parameter for an unkeyed hash.
- One primitive for each task: (X)ChaCha20-Poly1305, BLAKE2b, Argon2id, X25519, and Ed25519.
- No 128-bit keys: the minimum and universally recommended size is 256 bits.
- Public constants: easy to create buffers.
- Same vocabulary for everything: key, nonce, salt, input keying material, output keying material, etc.
- Consistent parameter ordering: buffers come first.
- Some low-level functions: useful for custom constructions.
- Full misuse resistance (e.g. no nonces or optional nonces). This can limit the user, doesn't work well with spans, and overcomplicates code.
- Solving the key reuse problem (e.g. a mandatory context for everything or wrappers instead of naked bytes). I'm not convinced either tactic works, and it again adds complexity.
- Other primitives unless they solve a problem. AES-GCM causes problems (e.g. it requires hardware support).
- Experimental ideas/custom constructions (e.g. anything without an RFC or Internet Draft), which can go in a separate project.
- Duplicate methods that return byte arrays.
- Unnecessary 'convenience' functions, like
GenerateKey()in almost every class.
- Guarded heap allocations, which would add complexity and aren't the fastest.
A big thanks to: