Skip to content

Commit

Permalink
feat(crypto): ✨ add Sha256 and X25519 APIs, and use Span based APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonboukheir committed Sep 6, 2023
1 parent 2d4a515 commit 22cd7fd
Show file tree
Hide file tree
Showing 27 changed files with 380 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Algorand.Unity.LowLevel;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System;

namespace Algorand.Unity.Crypto
{
Expand All @@ -9,31 +7,39 @@ public static partial class ChaCha20Poly1305
public enum DecryptionError
{
None = 0,
VerificationFailed = -1
VerificationFailed = -1,
InvalidMessageLength = 1
}

public static unsafe DecryptionError Decrypt<TCipher>(
NativeList<byte> message,
TCipher cipher,
public static unsafe DecryptionError Decrypt(
Span<byte> message,
ReadOnlySpan<byte> cipher,
Key key,
Nonce nonce
)
where TCipher : struct, IByteArray
{
message.Length = cipher.Length - AuthTag.Size;
var errorCode = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
message.GetUnsafePtr(),
out var messageLength,
null,
cipher.GetUnsafePtr(),
(ulong)cipher.Length,
null,
0,
nonce.GetUnsafePtr(),
key.GetUnsafePtr()
);
message.Length = (int)messageLength;
if (message.Length != cipher.Length - AuthTag.Size)
{
return DecryptionError.InvalidMessageLength;
}

var errorCode = 0;
fixed (byte* m = &message[0])
fixed (byte* c = &cipher[0])
{
errorCode = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
m,
out _,
null,
c,
(ulong)cipher.Length,
null,
0,
nonce.GetUnsafePtr(),
key.GetUnsafePtr()
);
}
return (DecryptionError)errorCode;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,53 @@
using Algorand.Unity.LowLevel;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System;

namespace Algorand.Unity.Crypto
{
public static partial class ChaCha20Poly1305
{
public enum EncryptionError
{
None = 0
None = 0,
CipherInvalidSize = 1,
}

public static unsafe EncryptionError Encrypt<TMessage>(
NativeList<byte> cipher,
TMessage message,
/// <summary>
/// Encrypt a message using the ChaCha20Poly1305 algorithm.
/// </summary>
/// <param name="cipher">The encrypted message.</param>
/// <param name="message">The message to encrypt.</param>
/// <param name="key">The symmetric key to encrypt with.</param>
/// <param name="nonce">The 12 byte iv to use to encrypt.</param>
/// <returns></returns>
public static unsafe EncryptionError Encrypt(
Span<byte> cipher,
ReadOnlySpan<byte> message,
Key key,
Nonce nonce
)
where TMessage : struct, IByteArray
{
cipher.Length = message.Length + AuthTag.Size;
var errorCode = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(
cipher.GetUnsafePtr(),
out var cipherLength,
message.GetUnsafePtr(),
(ulong)message.Length,
null,
0,
null,
nonce.GetUnsafePtr(),
key.GetUnsafePtr()
);
cipher.Length = (int)cipherLength;
nonce += 1;
var cipherLength = message.Length + AuthTag.Size;
if (cipher.Length != cipherLength)
{
return EncryptionError.CipherInvalidSize;
}
var errorCode = default(int);

fixed (byte* c = &cipher[0])
fixed (byte* m = &message[0])
{
errorCode = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(
c,
out _,
m,
(ulong)message.Length,
null,
0,
null,
nonce.GetUnsafePtr(),
key.GetUnsafePtr()
);
}
return (EncryptionError)errorCode;
}
}
}
}
16 changes: 16 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Ed25519/Ed25519+SecretKeyHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ public readonly unsafe Signature Sign<TMessage>(TMessage message)
Ptr);
return signature;
}

public readonly unsafe Signature Sign(ReadOnlySpan<byte> message)
{
var signature = new Signature();
fixed (byte* mPtr = &message.GetPinnableReference())
{
crypto_sign_ed25519_detached(
&signature,
out _,
mPtr,
(ulong)message.Length,
Ptr);
}

return signature;
}
}
}
}
17 changes: 17 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Ed25519/Ed25519+Signature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ public bool Verify<TMessage>(TMessage message, PublicKey pk)
}
}

public bool Verify(ReadOnlySpan<byte> message, PublicKey pk)
{
unsafe
{
fixed (byte* m = message)
fixed (Signature* s = &this)
{
var error = crypto_sign_ed25519_verify_detached(
s,
m,
(ulong)message.Length,
&pk);
return error == 0;
}
}
}

public override bool Equals(object obj)
{
return ByteArray.Equals(this, obj);
Expand Down
31 changes: 31 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Interop/sodium/sodium+CryptoBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Runtime.InteropServices;

namespace Algorand.Unity.Crypto
{
internal static unsafe partial class sodium
{
internal const ulong crypto_box_PUBLICKEYBYTES = 32U;
internal const ulong crypto_box_SECRETKEYBYTES = 32U;
internal const ulong crypto_box_NONCEBYTES = 24U;

[DllImport(Library, CallingConvention = CallingConvention.Cdecl)]
internal static extern int crypto_box_keypair(
void* pk,
void* sk);

[DllImport(Library, CallingConvention = CallingConvention.Cdecl)]
internal static extern int crypto_box_seed_keypair(
void* pk,
void* sk,
void* seed);

[DllImport(Library, CallingConvention = CallingConvention.Cdecl)]
internal static extern int crypto_box_easy(
void* c,
void* m,
ulong mlen,
void* n,
void* pk,
void* sk);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Interop/sodium/sodium+Sha256.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Runtime.InteropServices;

namespace Algorand.Unity.Crypto
{
internal static unsafe partial class sodium
{
[DllImport(Library, CallingConvention = CallingConvention.Cdecl)]
internal static extern int crypto_hash_sha256(
void* outp,
void* inp,
ulong inlen);
}
}
11 changes: 11 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Interop/sodium/sodium+Sha256.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Random.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,13 @@ public static void Randomize<T>(T bytes)
{
randombytes_buf(bytes.GetUnsafePtr(), (UIntPtr)bytes.Length);
}

public static void Randomize(Span<byte> bytes)
{
fixed (byte* ptr = bytes)
{
randombytes_buf(ptr, (UIntPtr)bytes.Length);
}
}
}
}
47 changes: 47 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Sha256.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Runtime.InteropServices;
using Algorand.Unity.LowLevel;

namespace Algorand.Unity.Crypto
{
[Serializable]
[StructLayout(LayoutKind.Explicit, Size = Size)]
public struct Sha256 : IByteArray, IEquatable<Sha256>
{
public const int Size = 256 / 8;

[FieldOffset(0)]
internal unsafe fixed ulong buffer[Size / 8];

public int Length => Size;

public byte this[int index]
{
get => this.GetByteAt(index);
set => this.SetByteAt(index, value);
}

public unsafe void* GetUnsafePtr()
{
fixed (void* b = buffer)
{
return b;
}
}

public bool Equals(Sha256 other)
{
return ByteArray.Equals(this, other);
}

public unsafe static Sha256 Hash(ReadOnlySpan<byte> message)
{
fixed (byte* messagePtr = message)
{
var hash = default(Sha256);
sodium.crypto_hash_sha256(&hash, messagePtr, (ulong)message.Length);
return hash;
}
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Algorand.Unity.Crypto/Sha256.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion Runtime/Algorand.Unity.Crypto/Sha512/Sha512.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ public static Sha512_256_Hash Hash256Truncated(NativeArray<byte>.ReadOnly bytes)
}
}

public static Sha512_256_Hash Hash256Truncated(ReadOnlySpan<byte> bytes)
{
unsafe
{
fixed (byte* ptr = bytes)
{
return Hash256Truncated(ptr, bytes.Length);
}
}
}

public static unsafe Sha512_256_Hash Hash256Truncated(byte* ptr, int length)
{
var result = new Sha512_256_Hash();
Expand All @@ -50,4 +61,4 @@ public static unsafe Sha512_256_Hash Hash256Truncated(byte* ptr, int length)
return result;
}
}
}
}
8 changes: 8 additions & 0 deletions Runtime/Algorand.Unity.Crypto/X25519.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions Runtime/Algorand.Unity.Crypto/X25519/X25519+Keygen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Algorand.Unity.Crypto
{
public static partial class X25519
{
public static (PublicKey publicKey, SecretKey secretKey) Keygen()
{
var publicKey = default(PublicKey);
var secretKey = default(SecretKey);

unsafe
{
sodium.crypto_box_keypair(&publicKey, &secretKey);
}
return (publicKey, secretKey);
}
}
}
Loading

0 comments on commit 22cd7fd

Please sign in to comment.