internal byte[] Initialize(byte[] password) { // initialize the lanes var blake2 = new HMACBlake2B(512); var dataStream = new LittleEndianActiveStream(); dataStream.Expose(DegreeOfParallelism); dataStream.Expose(_tagLine); dataStream.Expose(MemorySize); dataStream.Expose(Iterations); dataStream.Expose((uint)0x13); dataStream.Expose((uint)Type); dataStream.Expose(password.Length); dataStream.Expose(password); dataStream.Expose(Salt?.Length ?? 0); dataStream.Expose(Salt); dataStream.Expose(Secret?.Length ?? 0); dataStream.Expose(Secret); dataStream.Expose(AssociatedData?.Length ?? 0); dataStream.Expose(AssociatedData); blake2.Initialize(); var blockhash = blake2.ComputeHash(dataStream); dataStream.ClearBuffer(); return(blockhash); }
internal async Task <Argon2Lane[]> InitializeLanes(byte[] password) { var blockHash = Initialize(password); var lanes = new Argon2Lane[DegreeOfParallelism]; // adjust memory size if needed so that each segment has // an even size var segmentLength = MemorySize / (lanes.Length * 4); MemorySize = segmentLength * 4 * lanes.Length; var blocksPerLane = MemorySize / lanes.Length; if (blocksPerLane < 4) { throw new InvalidOperationException($"Memory should be enough to provide at least 4 blocks per {nameof(DegreeOfParallelism)}"); } Task[] init = new Task[lanes.Length * 2]; for (var i = 0; i < lanes.Length; ++i) { lanes[i] = new Argon2Lane(blocksPerLane); int taskIndex = i * 2; int iClosure = i; init[taskIndex] = Task.Run(() => { var stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(0); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][0], stream); }); init[taskIndex + 1] = Task.Run(() => { var stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(1); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][1], stream); }); } await Task.WhenAll(init).ConfigureAwait(false); Array.Clear(blockHash, 0, blockHash.Length); return(lanes); }
private byte[] Finalize(Argon2Lane[] lanes) { XorLanes(lanes); var ds = new LittleEndianActiveStream(); ds.Expose(lanes[0][lanes[0].BlockCount - 1]); ModifiedBlake2.Blake2Prime(lanes[0][1], ds, _tagLine); var result = new byte[_tagLine]; var tmp = MemoryMarshal.Cast <ulong, byte>(lanes[0][1].Span).Slice(0, result.Length); tmp.CopyTo(result); return(result); }
private byte[] Finalize(Argon2Lane[] lanes) { XorLanes(lanes); var ds = new LittleEndianActiveStream(); ds.Expose(lanes[0][lanes[0].BlockCount - 1]); ModifiedBlake2.Blake2Prime(lanes[0][1], ds, _tagLine); var result = new byte[_tagLine]; var stream = new Argon2Memory.Stream(lanes[0][1]); stream.Read(result, 0, _tagLine); return(result); }
public static void Blake2Prime(Memory <ulong> memory, LittleEndianActiveStream dataStream, int size = -1) { var hashStream = new LittleEndianActiveStream(); if (size < 0 || size > (memory.Length * 8)) { size = memory.Length * 8; } hashStream.Expose(size); hashStream.Expose(dataStream); if (size <= 64) { var blake2 = new HMACBlake2B(8 * size); blake2.Initialize(); memory.Span.Blit(blake2.ComputeHash(hashStream).AsSpan().Slice(0, size), 0); } else { var blake2 = new HMACBlake2B(512); blake2.Initialize(); int offset = 0; var chunk = blake2.ComputeHash(hashStream); memory.Span.Blit(chunk.AsSpan().Slice(0, 32), offset); // copy half of the chunk offset += 4; size -= 32; while (size > 64) { blake2.Initialize(); chunk = blake2.ComputeHash(chunk); memory.Span.Blit(chunk.AsSpan().Slice(0, 32), offset); // half again offset += 4; size -= 32; } blake2 = new HMACBlake2B(size * 8); blake2.Initialize(); memory.Span.Blit(blake2.ComputeHash(chunk).AsSpan().Slice(0, size), offset); // copy the rest } }