Skip to content

Commit

Permalink
Security Improvements: Introduction of SecureBigInteger
Browse files Browse the repository at this point in the history
Resolves: No entry
  • Loading branch information
shinji-san committed Nov 17, 2024
1 parent eb365a1 commit 0abf23b
Show file tree
Hide file tree
Showing 17 changed files with 3,332 additions and 115 deletions.
5 changes: 5 additions & 0 deletions src/Cryptography/ShamirsSecretSharing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ namespace SecretSharingDotNet.Cryptography;
/// </summary>
public abstract class ShamirsSecretSharing
{
/// <summary>
/// The minimum number of shares required to reconstruct the secret
/// </summary>
protected const int MinimumShareLimit = 2;

/// <summary>
/// Saves the known security levels (Mersenne prime exponents)
/// </summary>
Expand Down
36 changes: 29 additions & 7 deletions src/Cryptography/ShamirsSecretSharing`3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public Shares<TNumber> MakeShares(TNumber numberOfMinimumShares, TNumber numberO

int min = ((Calculator<TNumber>)numberOfMinimumShares).ToInt32();
int max = ((Calculator<TNumber>)numberOfShares).ToInt32();
if (min < 2)
if (min < MinimumShareLimit)
{
throw new ArgumentOutOfRangeException(nameof(numberOfMinimumShares), numberOfMinimumShares, ErrorMessages.MinNumberOfSharesLowerThanTwo);
}
Expand Down Expand Up @@ -192,7 +192,7 @@ public Shares<TNumber> MakeShares(TNumber numberOfMinimumShares, TNumber numberO
{
int min = ((Calculator<TNumber>)numberOfMinimumShares).ToInt32();
int max = ((Calculator<TNumber>)numberOfShares).ToInt32();
if (min < 2)
if (min < MinimumShareLimit)
{
throw new ArgumentOutOfRangeException(nameof(numberOfMinimumShares), numberOfMinimumShares, ErrorMessages.MinNumberOfSharesLowerThanTwo);
}
Expand Down Expand Up @@ -220,18 +220,40 @@ public Shares<TNumber> MakeShares(TNumber numberOfMinimumShares, TNumber numberO
/// </summary>
/// <param name="numberOfMinimumShares">Minimum number of shared secrets for reconstruction</param>
/// <returns></returns>
#if NET6_0_OR_GREATER
private unsafe Calculator<TNumber>[] CreatePolynomial(int numberOfMinimumShares)
#else
private Calculator<TNumber>[] CreatePolynomial(int numberOfMinimumShares)
#endif
{
var polynomial = new Calculator<TNumber>[numberOfMinimumShares];
polynomial[0] = Calculator<TNumber>.Zero;
byte[] randomNumber = new byte[this.mersennePrime.ByteCount];
using var rng = RandomNumberGenerator.Create();
for (int i = 1; i < numberOfMinimumShares; i++)
#if NET6_0_OR_GREATER
fixed (byte* pointer = randomNumber)
{
rng.GetBytes(randomNumber);
polynomial[i] = (Calculator.Create(randomNumber, typeof(TNumber)) as Calculator<TNumber>)?.Abs() % this.mersennePrime;
}
var span = new Span<byte>(pointer, this.mersennePrime.ByteCount);
using var rng = RandomNumberGenerator.Create();
for (int i = 1; i < numberOfMinimumShares; i++)
{
rng.GetBytes(span);
polynomial[i] = (Calculator.Create(randomNumber, typeof(TNumber)) as Calculator<TNumber>)?.Abs() %
this.mersennePrime;
}

span.Clear();
}
#else
using var rng = RandomNumberGenerator.Create();
for (int i = 1; i < numberOfMinimumShares; i++)
{
rng.GetBytes(randomNumber);
polynomial[i] = (Calculator.Create(randomNumber, typeof(TNumber)) as Calculator<TNumber>)?.Abs() %
this.mersennePrime;
}

Array.Clear(randomNumber, 0, randomNumber.Length);
#endif
return polynomial;
}

Expand Down
3 changes: 2 additions & 1 deletion src/Cryptography/SharedSeparator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ internal static class SharedSeparator
/// Separator array for <see cref="string.Split(char[])"/> method usage to avoid allocation of a new array.
/// </summary>
internal static readonly char[] CoordinateSeparatorArray = [CoordinateSeparator];
}
}

85 changes: 85 additions & 0 deletions src/Helper/CompositeDisposable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#if NET6_0_OR_GREATER
namespace SecretSharingDotNet.Helper;

using System;
using System.Collections.Concurrent;

/// <summary>
/// Manages a composite collection of <see cref="IDisposable"/> objects,
/// ensuring all contained disposables are disposed together.
/// </summary>
public sealed class CompositeDisposable : IDisposable
{
private readonly ConcurrentBag<IDisposable> disposables = new();
private bool disposed;

/// <summary>
/// Finalizes an instance of the <see cref="CompositeDisposable"/> class.
/// </summary>
~CompositeDisposable()
{
this.Dispose(false);
}

/// <summary>
/// Adds a disposable object to the composite collection of disposables.
/// </summary>
/// <param name="disposable">The disposable object to add.</param>
/// <exception cref="ObjectDisposedException">Thrown when the composite disposable has already been disposed.</exception>
public void Add(IDisposable disposable)
{
ArgumentNullException.ThrowIfNull(disposable);
if (this.disposed)
{
throw new ObjectDisposedException(nameof(CompositeDisposable));
}

this.disposables.Add(disposable);
}

/// <summary>
/// Clears and disposes all disposable objects contained within the composite collection.
/// </summary>
public void Clear()
{
foreach (var disposable in this.disposables)
{
disposable.Dispose();
}

this.disposables.Clear();
}

/// <summary>
/// Disposes the composite collection of disposables, releasing all managed resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary>
/// Disposes the composite collection of disposables, releasing all managed resources.
/// </summary>
/// <param name="disposing">Indicates whether the method call comes from a Dispose method (true) or from a finalizer (false).</param>
private void Dispose(bool disposing)
{
if (this.disposed)
{
return;
}

if (disposing)
{
foreach (var disposable in this.disposables)
{
disposable.Dispose();
}
}

this.disposables.Clear();
this.disposed = true;
}
}
#endif
28 changes: 28 additions & 0 deletions src/Helper/CompositeDisposableContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#if NET6_0_OR_GREATER

namespace SecretSharingDotNet.Helper;

using System.Threading;

/// <summary>
/// Provides a context for managing a <see cref="CompositeDisposable"/> instance per thread.
/// </summary>
public static class CompositeDisposableContext
{
/// <summary>
/// Provides a thread-local instance of <see cref="CompositeDisposable"/> that represents
/// the current context for managing disposable resources within the thread.
/// </summary>
public static ThreadLocal<CompositeDisposable> Current { get; } = new ThreadLocal<CompositeDisposable>();

/// <summary>
/// Sets the current thread's <see cref="CompositeDisposable"/> instance.
/// </summary>
/// <param name="compositeDisposable">The <see cref="CompositeDisposable"/> instance to set for the current thread.</param>
public static void SetCurrent(CompositeDisposable compositeDisposable)
{
Current.Value = compositeDisposable;
}
}

#endif
110 changes: 110 additions & 0 deletions src/Helper/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,114 @@ public static TArray[] Subset<TArray>(this TArray[] array, int index, int count)
Array.Copy(array,index, subset, 0, count);
return subset;
}

#if NET6_0_OR_GREATER
/// <summary>
/// Extends the byte array to a length that is a multiple of the size of an unsigned integer (UInt32).
/// </summary>
/// <param name="byteArray">The byte array representing a big integer.</param>
/// <returns>A span of bytes with the length extended to a multiple of the size of UInt32.</returns>
public static Span<byte> ExtendToMultipleOfUInt(this Span<byte> byteArray)
{
int newLength = (byteArray.Length + sizeof(uint) - 1) / sizeof(uint) * sizeof(uint);
byte[] extendedArray = new byte[newLength];
byteArray.CopyTo(extendedArray);
return new Span<byte>(extendedArray);
}

/// <summary>
/// Trims trailing zeroes from the provided span of bytes.
/// </summary>
/// <param name="bytes">The span of bytes from which to trim trailing zeroes.</param>
/// <returns>A span of bytes with trailing zeroes removed.</returns>
public static Span<byte> TrimTrailingZeroes(this Span<byte> bytes)
{
int length = bytes.Length;
for (int i = bytes.Length - 1; i >= 0; i--)
{
if (bytes[i] == 0)
{
length--;
}
else
{
break;
}
}

return bytes[..length];
}

/// <summary>
/// Applies two's complement to the given byte array, returning a new array
/// where each byte is the bitwise complement of the original with an increment of 1.
/// </summary>
/// <param name="bytes">The byte array to which the two's complement is to be applied.</param>
/// <returns>A new byte array that represents the two's complement of the input byte array.</returns>
public static Span<byte> ApplyTwoComplement(this Span<byte> bytes)
{
byte[] complementArray = new byte[bytes.Length];
for (int i = 0; i < bytes.Length; i++)
{
complementArray[i] = (byte)~bytes[i];
}

bool carry = true;
for (int i =0; i < complementArray.Length; i++)
{
if (!carry)
{
continue;
}

if (complementArray[i] == byte.MaxValue)
{
complementArray[i] = 0;
}
else
{
complementArray[i]++;
carry = false;
}
}

return complementArray;
}

/// <summary>
/// Reverses the two's complement representation of a byte sequence and returns the original byte array.
/// </summary>
/// <param name="complementArray">The byte array in two's complement form.</param>
/// <returns>A byte array representing the original binary number before two's complement was applied.</returns>
public static Span<byte> ReverseTwoComplement(this Span<byte> complementArray)
{
byte[] originalArray = new byte[complementArray.Length];
bool borrow = true;
for (int i = 0; i < complementArray.Length; i++)
{
if (borrow)
{
if (complementArray[i] == 0)
{
originalArray[i] = byte.MaxValue;
}
else
{
originalArray[i] = (byte)(complementArray[i] - 1);
borrow = false;
}
}
else
{
originalArray[i] = complementArray[i];
}
}
for(int i = 0; i < complementArray.Length; i++)
{
originalArray[i] = (byte)~originalArray[i];
}

return originalArray;
}
#endif
}
55 changes: 55 additions & 0 deletions src/Helper/Scope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#if NET6_0_OR_GREATER

namespace SecretSharingDotNet.Helper;

using System;
using System.Collections.Concurrent;

public sealed class Scope : IDisposable

Check warning on line 8 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope'

Check warning on line 8 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope'
{
private readonly ConcurrentDictionary<Type, object> services = new();
private bool disposed;

~Scope()

Check warning on line 13 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.~Scope()'

Check warning on line 13 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.~Scope()'
{
this.Dispose(false);
}

public T GetScopedSingleton<T>() where T : class, new()

Check warning on line 18 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.GetScopedSingleton<T>()'

Check warning on line 18 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.GetScopedSingleton<T>()'
{
var type = typeof(T);
if (this.services.TryGetValue(type, out object service))
{
return service as T;
}

var newService = new T();
this.services.TryAdd(type, newService);
return newService;
}

public void Dispose()

Check warning on line 31 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.Dispose()'

Check warning on line 31 in src/Helper/Scope.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Scope.Dispose()'
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if (this.disposed)
{
return;
}

if (disposing)
{
foreach (IDisposable service in this.services.Values)
{
service?.Dispose();
}
}

this.disposed = true;
}
}
#endif
Loading

0 comments on commit 0abf23b

Please sign in to comment.