public unsafe void Encrypt(ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> source, Span <byte> destination, Span <byte> tag, ReadOnlySpan <byte> associatedData = default) { CheckInput(nonce, source, destination); ulong length = (ulong)source.Length << 3; Span <byte> counterBlock = _counterBlock.AsSpan(0, BlockSize); Span <byte> counter = counterBlock.Slice(12, 4); nonce.CopyTo(counterBlock); counter[0] = 0; counter[1] = 0; counter[2] = 0; counter[3] = 1; _crypto.Encrypt(counterBlock, tag); counter[3] = 2; uint c = 2; _gHash.Update(associatedData); while (!source.IsEmpty) { _crypto.Encrypt(counterBlock, _buffer); ++c; BinaryPrimitives.WriteUInt32BigEndian(counter, c); int n = Math.Min(source.Length, BlockSize); fixed(byte *pOut = destination) fixed(byte *pSource = source) fixed(byte *pBuffer = _buffer) { IntrinsicsUtils.Xor(pSource, pBuffer, pOut, n); } _gHash.Update(destination[..n]);
protected override unsafe void Xor(byte *stream, byte *source, byte *destination, int length) { IntrinsicsUtils.Xor(stream, source, destination, length); }
public unsafe void Encrypt(ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> source, Span <byte> destination, Span <byte> tag, ReadOnlySpan <byte> associatedData = default) { if (nonce.Length != NonceSize) { throw new ArgumentException(@"Nonce size must be 12 bytes", nameof(nonce)); } if (destination.Length != source.Length) { throw new ArgumentException(string.Empty, nameof(destination)); } var length = (ulong)source.Length << 3; var counterBlock = _counterBlock.AsSpan(0, BlockSize4); var counter0 = counterBlock.Slice(12, 4); var counter1 = counterBlock.Slice(28, 4); var counter2 = counterBlock.Slice(44, 4); var counter3 = counterBlock.Slice(60, 4); nonce.CopyTo(counterBlock); nonce.CopyTo(counterBlock.Slice(16)); nonce.CopyTo(counterBlock.Slice(32)); nonce.CopyTo(counterBlock.Slice(48)); counter0[0] = 0; counter0[1] = 0; counter0[2] = 0; counter0[3] = 1; counter1[0] = 0; counter1[1] = 0; counter1[2] = 0; counter1[3] = 3; counter2[0] = 0; counter2[1] = 0; counter2[2] = 0; counter2[3] = 4; counter3[0] = 0; counter3[1] = 0; counter3[2] = 0; counter3[3] = 5; _crypto.Encrypt(counterBlock, tag); counter0[3] = 2; _gHash.Update(associatedData); while (!source.IsEmpty) { _crypto.Encrypt4(counterBlock, _buffer); counter0.IncrementBe4(); counter1.IncrementBe4(); counter2.IncrementBe4(); counter3.IncrementBe4(); var n = Math.Min(source.Length, BlockSize4); fixed(byte *pOut = destination) fixed(byte *pSource = source) fixed(byte *pBuffer = _buffer) { IntrinsicsUtils.Xor(pSource, pBuffer, pOut, n); } _gHash.Update(destination.Slice(0, n)); source = source.Slice(n); destination = destination.Slice(n); } BinaryPrimitives.WriteUInt64BigEndian(_buffer, (ulong)associatedData.Length << 3); BinaryPrimitives.WriteUInt64BigEndian(_buffer.AsSpan(8), length); _gHash.Update(_buffer.AsSpan(0, TagSize)); _gHash.GetMac(_buffer); fixed(byte *pTag = tag) fixed(byte *pBuffer = _buffer) { IntrinsicsUtils.Xor16(pTag, pBuffer, pTag); } }