Last active
March 10, 2017 23:00
-
-
Save Drawaes/f8fac49a9f495bc94dea95c483c2f7db to your computer and use it in GitHub Desktop.
Cleanup in progress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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