Write out the high-level API I need.
This commit is contained in:
112
SpaceWizards.Sodium/CryptoAeadXChaCha20Poly1305Ietf.cs
Normal file
112
SpaceWizards.Sodium/CryptoAeadXChaCha20Poly1305Ietf.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
namespace SpaceWizards.Sodium;
|
||||
using static Interop.Libsodium;
|
||||
|
||||
/// <summary>
|
||||
/// Wrappers around the <c>crypto_aead_xchacha20poly1305_ietf_</c> APIs.
|
||||
/// </summary>
|
||||
public static class CryptoAeadXChaCha20Poly1305Ietf
|
||||
{
|
||||
static CryptoAeadXChaCha20Poly1305Ietf()
|
||||
{
|
||||
SodiumCore.EnsureInit();
|
||||
}
|
||||
|
||||
public const int NoncePublicBytes = (int)crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
|
||||
public const int KeyBytes = (int)crypto_aead_xchacha20poly1305_ietf_KEYBYTES;
|
||||
public const int AddBytes = (int)crypto_aead_xchacha20poly1305_ietf_ABYTES;
|
||||
|
||||
public static unsafe void Keygen(Span<byte> key)
|
||||
{
|
||||
if (key.Length != KeyBytes)
|
||||
throw new ArgumentException($"Key must be {nameof(KeyBytes)} bytes");
|
||||
|
||||
fixed (byte* k = key)
|
||||
{
|
||||
crypto_aead_xchacha20poly1305_ietf_keygen(k);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Keygen()
|
||||
{
|
||||
var key = new byte[KeyBytes];
|
||||
Keygen(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
public static unsafe bool Encrypt(
|
||||
Span<byte> cipher,
|
||||
out int cipherLength,
|
||||
ReadOnlySpan<byte> message,
|
||||
ReadOnlySpan<byte> additionalData,
|
||||
ReadOnlySpan<byte> noncePublic,
|
||||
ReadOnlySpan<byte> key)
|
||||
{
|
||||
if (cipher.Length < checked(message.Length + AddBytes))
|
||||
throw new ArgumentException("Destination is too short");
|
||||
|
||||
if (key.Length != KeyBytes)
|
||||
throw new ArgumentException($"Key must be {nameof(KeyBytes)} bytes");
|
||||
|
||||
if (noncePublic.Length != NoncePublicBytes)
|
||||
throw new ArgumentException($"Nonce must be {nameof(NoncePublicBytes)} bytes");
|
||||
|
||||
fixed (byte* c = cipher)
|
||||
fixed (byte* m = message)
|
||||
fixed (byte* ad = additionalData)
|
||||
fixed (byte* npub = noncePublic)
|
||||
fixed (byte* k = key)
|
||||
{
|
||||
ulong clen;
|
||||
var ret = crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
c, &clen,
|
||||
m, (ulong)message.Length,
|
||||
ad, (ulong)additionalData.Length,
|
||||
null,
|
||||
npub,
|
||||
k);
|
||||
|
||||
cipherLength = (int)clen;
|
||||
return ret == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe bool Decrypt(
|
||||
Span<byte> message,
|
||||
out int messageLength,
|
||||
ReadOnlySpan<byte> cipher,
|
||||
ReadOnlySpan<byte> additionalData,
|
||||
ReadOnlySpan<byte> noncePublic,
|
||||
ReadOnlySpan<byte> key)
|
||||
{
|
||||
if (cipher.Length < AddBytes)
|
||||
throw new ArgumentException("Input is too short");
|
||||
|
||||
if (message.Length < cipher.Length - AddBytes)
|
||||
throw new ArgumentException("Output is too short");
|
||||
|
||||
if (key.Length != KeyBytes)
|
||||
throw new ArgumentException($"Key must be {nameof(KeyBytes)} bytes");
|
||||
|
||||
if (noncePublic.Length != NoncePublicBytes)
|
||||
throw new ArgumentException($"Nonce must be {nameof(NoncePublicBytes)} bytes");
|
||||
|
||||
fixed (byte* c = cipher)
|
||||
fixed (byte* m = message)
|
||||
fixed (byte* ad = additionalData)
|
||||
fixed (byte* npub = noncePublic)
|
||||
fixed (byte* k = key)
|
||||
{
|
||||
ulong mlen;
|
||||
var ret = crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
m, &mlen,
|
||||
null,
|
||||
c, (ulong)cipher.Length,
|
||||
ad, (ulong)additionalData.Length,
|
||||
npub,
|
||||
k);
|
||||
|
||||
messageLength = (int)mlen;
|
||||
return ret == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
SpaceWizards.Sodium/CryptoBox.cs
Normal file
94
SpaceWizards.Sodium/CryptoBox.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
namespace SpaceWizards.Sodium;
|
||||
|
||||
using static Interop.Libsodium;
|
||||
|
||||
/// <summary>
|
||||
/// Wrappers around the <c>crypto_box</c> APIs.
|
||||
/// </summary>
|
||||
public static class CryptoBox
|
||||
{
|
||||
static CryptoBox()
|
||||
{
|
||||
SodiumCore.EnsureInit();
|
||||
}
|
||||
|
||||
public const int SealBytes = (int)crypto_box_SEALBYTES;
|
||||
public const int PublicKeyBytes = (int)crypto_box_PUBLICKEYBYTES;
|
||||
public const int SecretKeyBytes = (int)crypto_box_SECRETKEYBYTES;
|
||||
|
||||
public static unsafe bool KeyPair(Span<byte> publicKey, Span<byte> secretKey)
|
||||
{
|
||||
if (publicKey.Length != PublicKeyBytes)
|
||||
throw new ArgumentException($"Public key must be {nameof(PublicKeyBytes)} bytes.");
|
||||
|
||||
if (secretKey.Length != SecretKeyBytes)
|
||||
throw new ArgumentException($"Secret key must be {nameof(SecretKeyBytes)} bytes.");
|
||||
|
||||
fixed (byte* pk = publicKey)
|
||||
fixed (byte* sk = secretKey)
|
||||
{
|
||||
return crypto_box_keypair(pk, sk) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe bool Seal(Span<byte> cipher, ReadOnlySpan<byte> message, ReadOnlySpan<byte> publicKey)
|
||||
{
|
||||
if (cipher.Length < checked(message.Length + SealBytes))
|
||||
throw new ArgumentException("Destination is too short");
|
||||
|
||||
fixed (byte* c = cipher)
|
||||
fixed (byte* m = message)
|
||||
fixed (byte* pk = publicKey)
|
||||
{
|
||||
return crypto_box_seal(c, m, (ulong)message.Length, pk) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Seal(ReadOnlySpan<byte> message, ReadOnlySpan<byte> publicKey)
|
||||
{
|
||||
var cipher = new byte[message.Length + SealBytes];
|
||||
if (!Seal(cipher, message, publicKey))
|
||||
throw new SodiumException("Seal failed");
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public static unsafe bool SealOpen(
|
||||
Span<byte> message,
|
||||
ReadOnlySpan<byte> cipher,
|
||||
ReadOnlySpan<byte> publicKey,
|
||||
ReadOnlySpan<byte> secretKey)
|
||||
{
|
||||
if (cipher.Length < SealBytes)
|
||||
throw new ArgumentException("Input is too short");
|
||||
|
||||
if (message.Length < (cipher.Length - SealBytes))
|
||||
throw new ArgumentException("Destination is too short");
|
||||
|
||||
if (publicKey.Length != PublicKeyBytes)
|
||||
throw new ArgumentException($"Public key must be {nameof(PublicKeyBytes)} bytes.");
|
||||
|
||||
if (secretKey.Length != SecretKeyBytes)
|
||||
throw new ArgumentException($"Secret key must be {nameof(SecretKeyBytes)} bytes.");
|
||||
|
||||
fixed (byte* m = message)
|
||||
fixed (byte* c = cipher)
|
||||
fixed (byte* pk = publicKey)
|
||||
fixed (byte* sk = secretKey)
|
||||
{
|
||||
return crypto_box_seal_open(m, c, (ulong)cipher.Length, pk, sk) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] SealOpen(ReadOnlySpan<byte> cipher, ReadOnlySpan<byte> publicKey, ReadOnlySpan<byte> secretKey)
|
||||
{
|
||||
if (cipher.Length < SealBytes)
|
||||
throw new ArgumentException("Input is too short");
|
||||
|
||||
var message = new byte[cipher.Length - SealBytes];
|
||||
if (!SealOpen(message, cipher, publicKey, secretKey))
|
||||
throw new SodiumException("SealOpen failed");
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
26
SpaceWizards.Sodium/SodiumCore.cs
Normal file
26
SpaceWizards.Sodium/SodiumCore.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SpaceWizards.Sodium.Interop.Libsodium;
|
||||
|
||||
namespace SpaceWizards.Sodium;
|
||||
|
||||
public static class SodiumCore
|
||||
{
|
||||
/// <summary>
|
||||
/// Directly call <see cref="sodium_init"/>.
|
||||
/// </summary>
|
||||
/// <returns>0 on success, 1 if already initialized, -1 on initialize failure.</returns>
|
||||
/// <seealso cref="EnsureInit"/>
|
||||
public static int Init()
|
||||
{
|
||||
return sodium_init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to ensure libsodium is initialized, throwing if it fails to initialize.
|
||||
/// </summary>
|
||||
/// <exception cref="SodiumInitException">Thrown if initialization of libsodium failed.</exception>
|
||||
public static void EnsureInit()
|
||||
{
|
||||
if (Init() == -1)
|
||||
throw new SodiumInitException("Failed to init libsodium!");
|
||||
}
|
||||
}
|
||||
16
SpaceWizards.Sodium/SodiumException.cs
Normal file
16
SpaceWizards.Sodium/SodiumException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace SpaceWizards.Sodium;
|
||||
|
||||
public sealed class SodiumException : Exception
|
||||
{
|
||||
public SodiumException()
|
||||
{
|
||||
}
|
||||
|
||||
public SodiumException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SodiumException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
17
SpaceWizards.Sodium/SodiumInitException.cs
Normal file
17
SpaceWizards.Sodium/SodiumInitException.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SpaceWizards.Sodium;
|
||||
|
||||
[Serializable]
|
||||
public sealed class SodiumInitException : Exception
|
||||
{
|
||||
public SodiumInitException()
|
||||
{
|
||||
}
|
||||
|
||||
public SodiumInitException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SodiumInitException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,17 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PackageId>SpaceWizards.Sodium</PackageId>
|
||||
<Version>0.1.0</Version>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<Description>Simple API binding for libsodium.</Description>
|
||||
<NoWarn>CS1591</NoWarn>
|
||||
<PackageTags>libsodium</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SpaceWizards.Sodium.Interop\SpaceWizards.Sodium.Interop.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user