private void UInt32_To_LE(uint n, PinnedMemory <byte> bs, int off) { bs[off] = (byte)(n); bs[off + 1] = (byte)(n >> 8); bs[off + 2] = (byte)(n >> 16); bs[off + 3] = (byte)(n >> 24); }
/** * close the digest, producing the final digest value. The doFinal * call leaves the digest reset. * Key, salt and personal string remain. * * @param out the array the digest is to be copied into. * @param outOffset the offset into the out array the digest is to start at. */ public virtual void DoFinal(PinnedMemory <byte> output, int outOffset) { f0 = 0xFFFFFFFFFFFFFFFFUL; t0 += (ulong)_bufferPos; if (_bufferPos > 0 && t0 == 0) { t1++; } Compress(_buffer, 0); Array.Clear(_buffer, 0, _buffer.Length);// Holds eventually the key if input is null Array.Clear(_internalState, 0, _internalState.Length); for (var i = 0; i < _chainValue.Length && (i * 8 < _digestLength); i++) { var bytes = UInt64_To_LE(_chainValue[i]); if (i * 8 < _digestLength - 8) { Array.Copy(bytes, 0, output.ToArray(), outOffset + i * 8, 8); } else { Array.Copy(bytes, 0, output.ToArray(), outOffset + i * 8, _digestLength - (i * 8)); } } Array.Clear(_chainValue, 0, _chainValue.Length); Reset(); }
static void Main(string[] args) { var iv = new byte[16]; var key = new byte[32]; using var provider = new RNGCryptoServiceProvider(); provider.GetBytes(iv); provider.GetBytes(key); using var keyPin = new PinnedMemory <byte>(key, false); using var argon2 = new Argon2(keyPin, iv) { Addressing = Argon2.AddressType.DependentAddressing, HashLength = 64, MemoryCost = 65536, Lanes = 4, Threads = 2, TimeCost = 3 }; argon2.UpdateBlock(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 }, false), 0, 11); // caw caw caw in utf8 using var hash = new PinnedMemory <byte>(new byte[argon2.GetLength()]); argon2.DoFinal(hash, 0); Console.WriteLine(BitConverter.ToString(hash.ToArray())); }
private void OutputLength(PinnedMemory <byte> buf, int off, int len, string msg) { if (off + len > buf.Length) { throw new Exception(msg); } }
private ulong LE_To_UInt64(PinnedMemory <byte> bs, int off) { var lo = LE_To_UInt32(bs, off); var hi = LE_To_UInt32(bs, off + 4); return(((ulong)hi << 32) | (ulong)lo); }
private PinnedMemory <byte> UInt64_To_LE(ulong n) { var bs = new PinnedMemory <byte>(new byte[8]); UInt64_To_LE(n, bs, 0); return(bs); }
private void SetKey(PinnedMemory <byte> key) { if (key.Length != 32) { throw new ArgumentException("Poly1305 key must be 256 bits."); } // Extract r portion of key (and "clamp" the values) var t0 = LE_To_UInt32(key, 0); var t1 = LE_To_UInt32(key, 4); var t2 = LE_To_UInt32(key, 8); var t3 = LE_To_UInt32(key, 12); // NOTE: The masks perform the key "clamping" implicitly r0 = t0 & 0x03FFFFFFU; r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U; r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU; r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU; r4 = (t3 >> 8) & 0x000FFFFFU; // Precompute multipliers s1 = r1 * 5; s2 = r2 * 5; s3 = r3 * 5; s4 = r4 * 5; k0 = LE_To_UInt32(key, BlockSize + 0); k1 = LE_To_UInt32(key, BlockSize + 4); k2 = LE_To_UInt32(key, BlockSize + 8); k3 = LE_To_UInt32(key, BlockSize + 12); }
private uint LE_To_UInt32(PinnedMemory <byte> bs, int off) { return((uint)bs[off] | (uint)bs[off + 1] << 8 | (uint)bs[off + 2] << 16 | (uint)bs[off + 3] << 24); }
internal static uint LE_To_UInt32(PinnedMemory <byte> bs, int off) { return(bs[off] | ((uint)bs[off + 1] << 8) | ((uint)bs[off + 2] << 16) | ((uint)bs[off + 3] << 24)); }
protected virtual void Dispose(bool disposing) { if (disposing) { Value.Dispose(); PinnedMemory.Dispose(); } }
internal static void LE_To_UInt32(PinnedMemory <byte> bs, int bOff, uint[] ns, int nOff, int count) { for (var i = 0; i < count; ++i) { ns[nOff + i] = LE_To_UInt32(bs, bOff); bOff += 4; } }
/// <summary> /// Constructs a Poly1305 MAC. /// </summary> public Poly1305(PinnedMemory <byte> key) { _singleBytePin = new PinnedMemory <byte>(_singleByte); _currentBlockPin = new PinnedMemory <byte>(_currentBlock); SetKey(key); Reset(); }
private void SetKey(PinnedMemory <byte> key, byte[] nonce) { if (key.Length != 32) { throw new ArgumentException("Poly1305 key must be 256 bits."); } if (_dance && (nonce == null || nonce.Length != BlockSize)) { throw new ArgumentException("Poly1305 requires a 128 bit IV."); } // Extract r portion of key (and "clamp" the values) var t0 = LE_To_UInt32(key, 0); var t1 = LE_To_UInt32(key, 4); var t2 = LE_To_UInt32(key, 8); var t3 = LE_To_UInt32(key, 12); // NOTE: The masks perform the key "clamping" implicitly r0 = t0 & 0x03FFFFFFU; r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U; r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU; r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU; r4 = (t3 >> 8) & 0x000FFFFFU; // Precompute multipliers s1 = r1 * 5; s2 = r2 * 5; s3 = r3 * 5; s4 = r4 * 5; PinnedMemory <byte> kBytes; int kOff; if (!_dance) { kBytes = key.Clone(); kOff = BlockSize; } else { // Compute encrypted nonce with chacha20 kBytes = key.Clone(); kOff = 0; using var cipher = new ChaCha20.NetCore.ChaCha20(kBytes, nonce); cipher.UpdateBlock(nonce, 0, BlockSize); cipher.DoFinal(kBytes, 0); cipher.Reset(); } k0 = LE_To_UInt32(kBytes, kOff + 0); k1 = LE_To_UInt32(kBytes, kOff + 4); k2 = LE_To_UInt32(kBytes, kOff + 8); k3 = LE_To_UInt32(kBytes, kOff + 12); kBytes.Dispose(); }
private readonly uint[] _x = new uint[StateSize]; // internal buffer /// <summary> /// Creates a Salsa20 engine with a specific number of rounds. /// </summary> /// <param name="key"></param> /// <param name="iv"></param> public ChaCha20(PinnedMemory <byte> key, byte[] iv, int rounds = 20) { _keyStreamPin = new PinnedMemory <byte>(_keyStream); _engineStatePin = new PinnedMemory <uint>(_engineState); _xPin = new PinnedMemory <uint>(_x); Rounds = rounds; SetKey(key, iv); }
public GlfwMouseState() { var buttonsLength = (int)(MouseButton.Last + 1); _mb = MemoryBlockPool.Get(sizeof(KeyEvent) * buttonsLength * 2); _buttons = _mb.AllocPinnedMemory <KeyEvent>(buttonsLength); _previousButtons = _mb.AllocPinnedMemory <KeyEvent>(buttonsLength); }
/// <summary> /// Constructs a Poly1305 MAC with ChaCha20 cipher. /// </summary> public Poly1305ChaCha20(PinnedMemory <byte> key, byte[] salt) { _singleBytePin = new PinnedMemory <byte>(_singleByte); _currentBlockPin = new PinnedMemory <byte>(_currentBlock); _dance = true; SetKey(key, salt); Reset(); }
static void Main(string[] args) { // WARNING: It's unsafe to output pinned memory as a string, even using bitconverter however for the sake of learning this is done below. // DO NOT DO THIS IN YOUR APPLICATION, you should store your pinned data in it's native form so it will remain locked, and pinned in place // strings can't be pinned due to there nature, however, for example an array of char[] can be provided it's not converted back to string // This example shows how even if you have supplied bytes, they will be zero'd at creation. This is often the biggest mistake people make with this library. using (var pinZero = new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 })) { Console.WriteLine(BitConverter.ToString(pinZero.ToArray())); } // This example shows how you can populate pinned memory on creation without those bytes being zero'd. They will still be zero'd on free! using var pin = new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 }, false); Console.WriteLine(BitConverter.ToString(pin.ToArray())); pin.Dispose(); // This second write should be all zero's as the memory has been freed Console.WriteLine(BitConverter.ToString(pin.ToArray())); // This example shows how even if you have supplied bytes, they will be zero'd at creation. This is often the biggest mistake people make with this library. PinnedMemory <byte> pinPopulated; using (pinPopulated = new PinnedMemory <byte>(new byte[11])) { pinPopulated[0] = 65; //pinPopulated.Write(0, 63); pinPopulated[1] = 61; //pinPopulated.Write(1, 61); pinPopulated[2] = 77; //pinPopulated.Write(2, 77); pinPopulated[3] = 20; //pinPopulated.Write(3, 20); pinPopulated[4] = 63; //pinPopulated.Write(4, 63); pinPopulated[5] = 61; //pinPopulated.Write(5, 61); pinPopulated[6] = 77; //pinPopulated.Write(6, 77); pinPopulated[7] = 20; //pinPopulated.Write(7, 20); pinPopulated[8] = 63; //pinPopulated.Write(8, 63); pinPopulated[9] = 61; //pinPopulated.Write(9, 61); pinPopulated[10] = 77; //pinPopulated.Write(10, 77); Console.WriteLine(BitConverter.ToString(pinPopulated.ToArray())); } // This is an example of using a char array. using var cawPin = new PinnedMemory <char>(new [] { 'c', 'a', 'w', ' ', 'c', 'a', 'w', ' ', 'c', 'a', 'w' }, false); // This pin will be freed when the program exits. Console.WriteLine(cawPin.ToArray()); }
public void UpdateBlock(PinnedMemory <byte> value, int offset, int length) { DataLength(value, offset, length, "input buffer too short"); var block = new byte[length]; Array.Copy(value.ToArray(), offset, block, 0, length); _buffer = _buffer == null ? block : Append(_buffer, block); }
internal GlfwKeyboardState() { var keyEventsLength = ((int)Key.LastKey + 1); var size = sizeof(KeyEvent) * keyEventsLength * 2; _mb = MemoryBlockPool.Get(size); _keyEvents = _mb.AllocPinnedMemory <KeyEvent>(keyEventsLength); _previousKeyEvents = _mb.AllocPinnedMemory <KeyEvent>(keyEventsLength); }
public static void Poly() { using var poly = new Poly1305(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77 }, false)); using var hash = new PinnedMemory <byte>(new byte[poly.GetLength()]); // digest.UpdateBlock(new byte[] {63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77}, 0, 11); // This may be exposed without being pinned. poly.UpdateBlock(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 }, false), 0, 11); poly.DoFinal(hash, 0); Console.WriteLine(BitConverter.ToString(hash.ToArray())); }
private ulong f0 = 0UL; // finalization flag, for last block: ~0L // For Tree Hashing Mode, not used here: // private long f1 = 0L; // finalization flag, for last node: ~0L /** * Basic sized constructor - size in bits. * * @param digestSize size of the digest in bits */ public Blake2b(int digestSize = 512) { if (digestSize != 160 && digestSize != 256 && digestSize != 384 && digestSize != 512) { throw new ArgumentException("Blake2b digest restricted to one of [160, 256, 384, 512]"); } _buffer = new byte[BlockLengthBytes]; _bufferPin = new PinnedMemory <byte>(_buffer); _digestLength = digestSize / 8; Init(); }
protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { Value.Dispose(); PinnedMemory.Dispose(); } _disposed = true; }
private static void Mac() { // This is an example of hashing byte[] using PinnedMemory. This is the best method as it protects bytes during creation of the mac // and not just the output. It will also zero bytes after there written. However, raw byte[] is also accepted as shown in the commented version. var digest = new Blake2bMac(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77 }, false)); using var exampleHash = new PinnedMemory <byte>(new byte[digest.GetLength()]); // digest.UpdateBlock(new byte[] {63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77}, 0, 11); // This may be exposed without being pinned. digest.UpdateBlock(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 }, false), 0, 11); digest.DoFinal(exampleHash, 0); Console.WriteLine(BitConverter.ToString(exampleHash.ToArray())); }
public void DoFinal(PinnedMemory <byte> output, int outOff) { DataLength(output, outOff, BlockSize, "Output buffer is too short."); if (_currentBlockOffset > 0) { // Process padded block ProcessBlock(); } h1 += (h0 >> 26); h0 &= 0x3ffffff; h2 += (h1 >> 26); h1 &= 0x3ffffff; h3 += (h2 >> 26); h2 &= 0x3ffffff; h4 += (h3 >> 26); h3 &= 0x3ffffff; h0 += (h4 >> 26) * 5; h4 &= 0x3ffffff; h1 += (h0 >> 26); h0 &= 0x3ffffff; var g0 = h0 + 5; var b = g0 >> 26; g0 &= 0x3ffffff; var g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; var g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; var g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; var g4 = h4 + b - (1 << 26); b = (g4 >> 31) - 1; var nb = ~b; h0 = (h0 & nb) | (g0 & b); h1 = (h1 & nb) | (g1 & b); h2 = (h2 & nb) | (g2 & b); h3 = (h3 & nb) | (g3 & b); h4 = (h4 & nb) | (g4 & b); var f0 = ((h0) | (h1 << 26)) + (ulong)k0; var f1 = ((h1 >> 6) | (h2 << 20)) + (ulong)k1; var f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2; var f3 = ((h3 >> 18) | (h4 << 8)) + (ulong)k3; UInt32_To_LE((uint)f0, output, outOff); f1 += (f0 >> 32); UInt32_To_LE((uint)f1, output, outOff + 4); f2 += (f1 >> 32); UInt32_To_LE((uint)f2, output, outOff + 8); f3 += (f2 >> 32); UInt32_To_LE((uint)f3, output, outOff + 12); Reset(); }
public static void Mac() { var digest = new Blake2bMac(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77 }, false)); // This is a common, but could be unsafe example of dealing with strings from a form using text encoding. using var exampleHash = new PinnedMemory <byte>(new byte[digest.GetLength()]); var unsafeCaw = "caw caw caw"; // this is unsafe because string's can't be pinned and are subject to garbage collection, and being written to disk (pagefile). var caw = new PinnedMemory <byte>(Encoding.UTF8.GetBytes(unsafeCaw), false); // this is now safe but ONLY the variable caw, unsafeCaw is STILL exposed. unsafeCaw = string.Empty; // unsafeCaw COULD STILL exposed even tho we set it to empty because this depends on garbage collection getting around to clearing it. digest.UpdateBlock(caw, 0, caw.Length); digest.DoFinal(exampleHash, 0); Console.WriteLine(BitConverter.ToString(exampleHash.ToArray())); // This is a more uncommon but should be safer example of how to use strings with SecureString for input. using var exampleHash2 = new PinnedMemory <byte>(new byte[digest.GetLength()]); var secureCaw = new SecureString(); secureCaw.AppendChar('c'); secureCaw.AppendChar('a'); secureCaw.AppendChar('w'); secureCaw.AppendChar(' '); secureCaw.AppendChar('c'); secureCaw.AppendChar('a'); secureCaw.AppendChar('w'); secureCaw.AppendChar(' '); secureCaw.AppendChar('c'); secureCaw.AppendChar('a'); secureCaw.AppendChar('w'); secureCaw.MakeReadOnly(); using var pinnedCaw = new PinnedMemory <char>(new char[secureCaw.Length]); var cawPointer = Marshal.SecureStringToBSTR(secureCaw); for (var i = 0; i <= secureCaw.Length - 1; i++) { var c = (char)Marshal.ReadByte(cawPointer, i * 2); pinnedCaw[i] = c; } using var pinnedCawBytes = new PinnedMemory <byte>(Encoding.UTF8.GetBytes(pinnedCaw.ToArray()), false); digest.UpdateBlock(pinnedCawBytes, 0, secureCaw.Length); digest.DoFinal(exampleHash2, 0); Console.WriteLine(BitConverter.ToString(exampleHash2.ToArray())); }
static void Main(string[] args) { var iv = new byte[16]; var key = new byte[32]; using var provider = new RNGCryptoServiceProvider(); provider.GetBytes(iv); provider.GetBytes(key); using var keyPin = new PinnedMemory <byte>(key, false); using var cipher = new Poly1305ChaCha20(keyPin, iv); cipher.UpdateBlock(new PinnedMemory <byte>(new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 }, false), 0, 11); // caw caw caw in utf8 using var output = new PinnedMemory <byte>(new byte[cipher.GetLength()]); cipher.DoFinal(output, 0); Console.WriteLine(BitConverter.ToString(output.ToArray())); }
private ulong f0 = 0UL; // finalization flag, for last block: ~0L // For Tree Hashing Mode, not used here: // private long f1 = 0L; // finalization flag, for last node: ~0L /** * Blake2b for authentication ("Prefix-MAC mode"). * After calling the doFinal() method, the key will * remain to be used for further computations of * this instance. * The key can be overwritten using the clearKey() method. * * @param key A key up to 64 bytes or null */ public Blake2bMac(PinnedMemory <byte> key) { _buffer = new byte[BlockLengthBytes]; _bufferPin = new PinnedMemory <byte>(_buffer); if (key != null) { _key = key; if (_key.Length > 64) { throw new ArgumentException("Keys > 64 are not supported"); } _keyLength = _key.Length; Array.Copy(_key.ToArray(), 0, _buffer, 0, _keyLength); _bufferPos = BlockLengthBytes; // zero padding } _digestLength = 64; Init(); }
private void SetKey(PinnedMemory <byte> keyBytes, byte[] ivBytes) { if (keyBytes != null) { if (keyBytes.Length != 16 && keyBytes.Length != 32) { throw new ArgumentException("ChaCha20 requires 128 bit or 256 bit key"); } PackTauOrSigma(keyBytes.Length, _engineState, 0); // Key LE_To_UInt32(keyBytes, 0, _engineState, 4, 4); LE_To_UInt32(keyBytes, keyBytes.Length - 16, _engineState, 8, 4); } // IV LE_To_UInt32(ivBytes, 0, _engineState, 14, 2); }
/// <summary> /// Secure random number generator using Blake2b /// </summary> /// <param name="rounds">Number of rounds imposed on seeds (Default: 10)</param> /// <param name="seed">Auto seed by nano time, and digest size</param> public SecureRandom(int rounds = 10, bool seed = true) { _rounds = rounds; _digest = new Blake2b(); _seed = new PinnedMemory <byte>(new byte[_digest.GetLength()]); _seedCounter = 0; _state = new PinnedMemory <byte>(new byte[_digest.GetLength()]); _stateCounter = 1; if (!seed) { return; } _seedCounter = 2; AddSeedMaterial(NextCounterValue()); AddSeedMaterial(NextBytes(_digest.GetLength())); }
public void DoFinal(PinnedMemory <byte> output, int offset) { OutputLength(output, offset, _buffer.Length, "output buffer too short"); if (LimitExceeded((uint)_buffer.Length)) { throw new Exception("2^70 byte limit per IV would be exceeded; Change IV"); } for (var i = 0; i < _buffer.Length; i++) { if (_index == 0) { GenerateKeyStream(_keyStream); AdvanceCounter(); } output[i + offset] = (byte)(_keyStream[_index] ^ _buffer[i]); _index = (_index + 1) & 63; } }