Skip to content

Instantly share code, notes, and snippets.

@Drawaes
Last active March 10, 2017 23:00
Show Gist options
  • Save Drawaes/f8fac49a9f495bc94dea95c483c2f7db to your computer and use it in GitHub Desktop.
Save Drawaes/f8fac49a9f495bc94dea95c483c2f7db to your computer and use it in GitHub Desktop.
Cleanup in progress
using System;
using System.Buffers;
using System.Buffers.Pools;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
namespace Leto.BulkCipher
{
public sealed class AeadBulkCipher : IDisposable
{
private static readonly IntPtr s_zeroBuffer = Marshal.AllocHGlobal(byte.MaxValue);
private BufferPool _bufferPool;
private OwnedMemory<byte> _keyStore;
private byte[] _sequence;
private ulong _sequenceNumber;
private BulkKey _key;
private byte _paddingSize;
static AeadBulkCipher()
{
var array = new byte[byte.MaxValue];
Marshal.Copy(array, 0, s_zeroBuffer, array.Length);
}
internal AeadBulkCipher(IntPtr cipherType, BufferPool bufferPool, int ivLength, int keySize, int tagSize)
{
_bufferPool = bufferPool;
_keyStore = bufferPool.Rent(0);
_sequence = new byte[ivLength];
_key = new BulkKey(cipherType, _keyStore.Memory.Slice(0, keySize), _keyStore.Memory.Slice(keySize, ivLength), tagSize);
}
public byte PaddingSize { get => _paddingSize; set => _paddingSize = value; }
public int Overhead => _key.TagSize + _paddingSize;
public unsafe void SetKey(Span<byte> key)
{
key.CopyTo(_key.Key.Span);
}
public void SetIV(Span<byte> iv)
{
var localIv = _key.IV.Span;
for (var i = 0; i < localIv.Length; i++)
{
localIv[i] = (byte)(iv[i] ^ 0x0);
}
}
public void Decrypt(ref ReadableBuffer messageBuffer)
{
_key.Init(KeyMode.Decryption);
ReadTag(ref messageBuffer);
messageBuffer = messageBuffer.Slice(0, messageBuffer.Length - _key.TagSize);
foreach (var b in messageBuffer)
{
if (b.Length == 0) continue;
_key.Update(b.Span);
}
_key.Finish();
IncrementSequence();
}
private unsafe void ReadTag(ref ReadableBuffer messageBuffer)
{
var tagBuffer = messageBuffer.Slice(messageBuffer.Length - _key.TagSize);
tagBuffer.ToSpan();
Span<byte> tagSpan;
if (tagBuffer.IsSingleSpan)
{
tagSpan = tagBuffer.First.Span;
}
else
{
var tagStack = stackalloc byte[_key.TagSize];
tagSpan = new Span<byte>(tagStack, _key.TagSize);
tagBuffer.CopyTo(tagSpan);
}
_key.WriteTag(tagSpan);
}
public void IncrementSequence()
{
var vPtr = _key.IV.Span;
var i = vPtr.Length - 1;
while (i > 3)
{
unchecked
{
var val = vPtr[i] ^ _sequence[i];
_sequence[i] = (byte)(_sequence[i] + 1);
vPtr[i] = (byte)(_sequence[i] ^ val);
if (_sequence[i] > 0)
{
return;
}
}
i -= 1;
}
Alerts.AlertException.ThrowAlert(Alerts.AlertLevel.Fatal, Alerts.AlertDescription.decode_error, "Failed to increment sequence on Aead Cipher");
}
public void Dispose()
{
_key?.Dispose();
_key = null;
if (_keyStore != null)
{
_bufferPool.Return(_keyStore);
_keyStore = null;
}
GC.SuppressFinalize(this);
}
~AeadBulkCipher()
{
Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment