In a part of the project, I had to implement a solution for encapsulation of byte arrays. We do use ssh and secure ports for socket connection but I was in need of an extra layer of protection against man-in-the-middle attacks or a mechanism to drop packages rather fast before reading all the package content. (In case somebody sends an array with 10k elements, continuously to make denial of service). So I created this library which might help me in my case.
Project repo for further details.
CapsuleConstant Class:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace LiteByte{
/// <summary>
/// Class to generate instances for capsulation constants.
/// </summary>
public class CapsuleConstant : IComparable<CapsuleConstant>
{
private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
private byte val;
private int position;//0 is first
private bool head;
/// <summary>
/// Value property of an CapsuleConstant instance. Byte value for constant.
/// </summary>
public byte Val { get => val; set => val = value; }
/// <summary>
/// Position of the constant related to the start position parameter(head). Ex: if position is:0 and head=true, this constant will be the first element in the capsule.
/// </summary>
public int Position { get => position; set => position = value; }
/// <summary>
/// Property to indicate counting for position from start(head) or counting from the end(tail) of the capsule. Ex:Head:false, position:0 will be the last element of the capsule.
/// </summary>
public bool Head { get => head; set => head = value; }
/// <summary>
/// Base constructor of CapsuleConstant class to initiate instances.
/// </summary>
/// <param name="value"></param>
/// <param name="position"></param>
/// <param name="head"></param>
public CapsuleConstant(byte value, int position, bool head)
{
this.val = value;
if (position < 0)
{
throw new ArgumentOutOfRangeException();
}
this.position = position;
this.head = head;
}
private CapsuleConstant(byte value,int headCounter, int tailCounter,bool head)
{
this.val = value;
if (head)
{
this.position = headCounter;
}
else
{
this.position = tailCounter;
}
this.head = head;
}
/// <summary>
///
/// </summary>
/// <param name="amount">Values which vary from 1 to int.max()</param>
/// <returns></returns>
public static Stack<CapsuleConstant> GenerateCapsulationConstants(int amount)
{
try
{
uint unsignedAmount = Convert.ToUInt32(amount);
}
catch (Exception)
{
throw new ArgumentOutOfRangeException();
}
Stack<CapsuleConstant> capsuleConstants = new Stack<CapsuleConstant>();
byte[] randomHolder = new byte[1];
Random rnd = new Random();
int headCounter = -1;
int tailCounter = -1;
bool head;
for (int i = 0; i < amount; i++)
{//TODO stack to string conversion for console writeline, string
rngCsp.GetBytes(randomHolder);
if (rnd.NextDouble() >= 0.5)
{
head = true;
headCounter++;
}
else
{
head = false;
tailCounter++;
//TODO method for searching capsulation stack for certain stuff
}
capsuleConstants.Push(new CapsuleConstant(randomHolder[0], headCounter, tailCounter, head));
}
return capsuleConstants;
}
/// <summary>
/// Implementation of IEnumarable
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public int CompareTo(CapsuleConstant other)
{
return this.position.CompareTo(other.position);
}
}
}
Encapsulation method:
public byte[] ConvertToSyntax(byte[] infactData)
{
if (infactData == null)
{
throw new ArgumentNullException("infactData", "Byte array parameter infactData cannot be null");
}
Stack<CapsuleConstant> capsuleConstantsClone = StackClone<CapsuleConstant>(capsulationConstants);
int capsuleSize = infactData.Length + capsuleConstantsClone.Count;
byte[] capsule = new byte[capsuleSize];
while (capsuleConstantsClone.Count != 0)
{
CapsuleConstant constant = capsuleConstantsClone.Pop();
if (constant.Head)
{
capsule[constant.Position] = constant.Val;
}
else
{
capsule[(capsule.Length - 1) - constant.Position] = constant.Val;
}
}
CapsuleConstant maxHead = (from x in capsulationConstants where x.Head == true select x).Max();
Array.Copy(infactData, 0, capsule, maxHead.Position + 1, infactData.Length);
return capsule;
}
Example usage as follows:
Stack<CapsuleConstant> constants=CapsuleConstant.GenerateCapsulationConstants(100);
LiteByteCapsule lite=new LiteByteCapsule(constants);
byte[] innerPackage={99,255,0,35,42};
byte[] capsule=lite.ConvertToSyntax(innerPackage);
byte[] decapsulated=lite.CheckSyntax(capsule);
Unit Test of CheckSyntax (Using XUnit and no mock preset). It takes the most time among other tests. (~80 ms, other tests take about ~1ms. included in repository)
[Fact]
public void CheckSyntax_Base()
{
int amount = 100;
LiteByteCapsule lite = new LiteByteCapsule(CapsuleConstant.GenerateCapsulationConstants(amount));
byte[] package = { 99, 0, 255, 12, 33, 54, 123 };
byte[] capsule=lite.ConvertToSyntax(package);
byte[] inner=lite.CheckSyntax(capsule);
Assert.NotNull(inner);
Assert.NotEmpty(inner);
Assert.Equal(inner.Length, package.Length);
Assert.Equal(package, inner);
}
Current unit tests report no error. But i want to make it better. Because in case of encapsulation and de-encapsulation of a byte array for 1000 times it takes ~80ms. What can i improve, or should i change the whole structure and approach to the problem ?
Any idea and feedback helps. Thanks in advance.