/** * 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) { // 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()); }
private void AddSeedMaterial(byte[] inSeed) { lock (_lockObject) { _digest.UpdateBlock(inSeed, 0, inSeed.Length); _digest.UpdateBlock(_seed.ToArray(), 0, _seed.Length); _digest.DoFinal(_seed, 0); } }
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())); }
/** * Reset the digest back to it's initial state. * The key, the salt and the personal string will * remain for further computations. */ public virtual void Reset() { _bufferPos = 0; f0 = 0L; t0 = 0L; t1 = 0L; _chainValue = null; Array.Clear(_buffer, 0, _buffer.Length); if (_key != null) { Array.Copy(_key.ToArray(), 0, _buffer, 0, _key.Length); _bufferPos = BlockLengthBytes; // zero padding } Init(); }
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); }
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 void GenerateState() { AddCounter(_stateCounter++); _digest.UpdateBlock(_state.ToArray(), 0, _state.Length); _digest.UpdateBlock(_seed.ToArray(), 0, _seed.Length); _digest.DoFinal(_state, 0); if ((_stateCounter % _rounds) == 0) { CycleSeed(); } }
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 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(); }
public virtual void UpdateBlock(PinnedMemory <byte> message, int offset, int len) { UpdateBlock(message.ToArray(), offset, len); message.Dispose(); }
public void UpdateBlock(PinnedMemory <byte> value, int offset, int length) { UpdateBlock(value.ToArray(), offset, length); value.Dispose(); }
public void UpdateBlock(PinnedMemory <byte> input, int inOff, int len) { UpdateBlock(input.ToArray(), inOff, len); input.Dispose(); }