From 716a491e3ed312da6c80a74e327d62dd4388b11e Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 1 Nov 2022 14:39:54 +0700 Subject: More Span-based Stream methods --- crypto/src/asn1/Asn1OutputStream.cs | 16 ++- crypto/src/asn1/ConstructedBitStream.cs | 52 ++++++++++ crypto/src/asn1/ConstructedOctetStream.cs | 52 ++++++++++ crypto/src/asn1/DefiniteLengthInputStream.cs | 21 ++++ crypto/src/asn1/IndefiniteLengthInputStream.cs | 23 ++++- crypto/src/bcpg/ArmoredInputStream.cs | 21 ++++ crypto/src/bcpg/BcpgInputStream.cs | 41 +++++++- crypto/src/bcpg/BcpgOutputStream.cs | 112 +++++++++++++++------ .../src/cms/CMSAuthenticatedDataStreamGenerator.cs | 9 +- crypto/src/cms/CMSCompressedDataStreamGenerator.cs | 10 +- crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs | 9 +- crypto/src/cms/CMSSignedDataStreamGenerator.cs | 9 +- crypto/src/cms/CMSTypedStream.cs | 7 -- crypto/src/openpgp/PgpEncryptedData.cs | 29 ++++++ crypto/src/openpgp/WrappedGeneratorStream.cs | 5 +- crypto/src/tls/CombinedHash.cs | 8 ++ crypto/src/tls/DeferredHash.cs | 16 +++ crypto/src/tls/crypto/TlsHash.cs | 4 + crypto/src/tls/crypto/TlsHashSink.cs | 10 ++ crypto/src/tls/crypto/TlsMac.cs | 4 + crypto/src/tls/crypto/TlsMacSink.cs | 10 ++ crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs | 7 ++ crypto/src/tls/crypto/impl/bc/BcTlsHash.cs | 7 ++ crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs | 7 ++ crypto/src/util/io/BaseInputStream.cs | 4 + crypto/src/util/io/BaseOutputStream.cs | 3 + crypto/src/util/io/FilterStream.cs | 23 ++++- 27 files changed, 462 insertions(+), 57 deletions(-) diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs index 59178ea31..163e3848c 100644 --- a/crypto/src/asn1/Asn1OutputStream.cs +++ b/crypto/src/asn1/Asn1OutputStream.cs @@ -1,5 +1,10 @@ using System; using System.IO; +using System.Diagnostics; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +using System.Buffers.Binary; +using System.Numerics; +#endif using Org.BouncyCastle.Utilities.IO; @@ -73,15 +78,19 @@ namespace Org.BouncyCastle.Asn1 { if (dl < 128) { + Debug.Assert(dl >= 0); WriteByte((byte)dl); return; } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span stack = stackalloc byte[5]; + Span encoding = stackalloc byte[5]; + BinaryPrimitives.WriteUInt32BigEndian(encoding[1..], (uint)dl); + int leadingZeroBytes = BitOperations.LeadingZeroCount((uint)dl) / 8; + encoding[leadingZeroBytes] = (byte)(0x84 - leadingZeroBytes); + Write(encoding[leadingZeroBytes..]); #else byte[] stack = new byte[5]; -#endif int pos = stack.Length; do @@ -94,9 +103,6 @@ namespace Org.BouncyCastle.Asn1 int count = stack.Length - pos; stack[--pos] = (byte)(0x80 | count); -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Write(stack[pos..]); -#else Write(stack, pos, count + 1); #endif } diff --git a/crypto/src/asn1/ConstructedBitStream.cs b/crypto/src/asn1/ConstructedBitStream.cs index 49f54fc1b..f089dac75 100644 --- a/crypto/src/asn1/ConstructedBitStream.cs +++ b/crypto/src/asn1/ConstructedBitStream.cs @@ -33,6 +33,9 @@ namespace Org.BouncyCastle.Asn1 { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else if (count < 1) return 0; @@ -75,8 +78,57 @@ namespace Org.BouncyCastle.Asn1 m_currentStream = m_currentParser.GetBitStream(); } } +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + if (buffer.IsEmpty) + return 0; + + if (m_currentStream == null) + { + if (!m_first) + return 0; + + m_currentParser = GetNextParser(); + if (m_currentParser == null) + return 0; + + m_first = false; + m_currentStream = m_currentParser.GetBitStream(); + } + + int totalRead = 0; + + for (;;) + { + int numRead = m_currentStream.Read(buffer[totalRead..]); + + if (numRead > 0) + { + totalRead += numRead; + + if (totalRead == buffer.Length) + return totalRead; + } + else + { + m_padBits = m_currentParser.PadBits; + m_currentParser = GetNextParser(); + if (m_currentParser == null) + { + m_currentStream = null; + return totalRead; + } + + m_currentStream = m_currentParser.GetBitStream(); + } + } + } +#endif + public override int ReadByte() { if (m_currentStream == null) diff --git a/crypto/src/asn1/ConstructedOctetStream.cs b/crypto/src/asn1/ConstructedOctetStream.cs index 12aa14e74..d005f9fe7 100644 --- a/crypto/src/asn1/ConstructedOctetStream.cs +++ b/crypto/src/asn1/ConstructedOctetStream.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using Org.BouncyCastle.Utilities; @@ -22,6 +23,9 @@ namespace Org.BouncyCastle.Asn1 { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else if (count < 1) return 0; @@ -63,8 +67,56 @@ namespace Org.BouncyCastle.Asn1 m_currentStream = next.GetOctetStream(); } } +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + if (buffer.IsEmpty) + return 0; + + if (m_currentStream == null) + { + if (!m_first) + return 0; + + Asn1OctetStringParser next = GetNextParser(); + if (next == null) + return 0; + + m_first = false; + m_currentStream = next.GetOctetStream(); + } + + int totalRead = 0; + + for (;;) + { + int numRead = m_currentStream.Read(buffer[totalRead..]); + + if (numRead > 0) + { + totalRead += numRead; + + if (totalRead == buffer.Length) + return totalRead; + } + else + { + Asn1OctetStringParser next = GetNextParser(); + if (next == null) + { + m_currentStream = null; + return totalRead; + } + + m_currentStream = next.GetOctetStream(); + } + } + } +#endif + public override int ReadByte() { if (m_currentStream == null) diff --git a/crypto/src/asn1/DefiniteLengthInputStream.cs b/crypto/src/asn1/DefiniteLengthInputStream.cs index ed5bd2446..89f0d5a62 100644 --- a/crypto/src/asn1/DefiniteLengthInputStream.cs +++ b/crypto/src/asn1/DefiniteLengthInputStream.cs @@ -79,6 +79,27 @@ namespace Org.BouncyCastle.Asn1 return numRead; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + if (_remaining == 0) + return 0; + + int toRead = System.Math.Min(buffer.Length, _remaining); + int numRead = _in.Read(buffer[..toRead]); + + if (numRead < 1) + throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining); + + if ((_remaining -= numRead) == 0) + { + SetParentEofDetect(); + } + + return numRead; + } +#endif + internal void ReadAllIntoByteArray(byte[] buf) { if (_remaining != buf.Length) diff --git a/crypto/src/asn1/IndefiniteLengthInputStream.cs b/crypto/src/asn1/IndefiniteLengthInputStream.cs index 1c8bd9a15..e192e9e8b 100644 --- a/crypto/src/asn1/IndefiniteLengthInputStream.cs +++ b/crypto/src/asn1/IndefiniteLengthInputStream.cs @@ -57,7 +57,28 @@ namespace Org.BouncyCastle.Asn1 return numRead + 1; } - public override int ReadByte() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + // Only use this optimisation if we aren't checking for 00 + if (_eofOn00 || buffer.Length <= 1) + return base.Read(buffer); + + if (_lookAhead < 0) + return 0; + + int numRead = _in.Read(buffer[1..]); + if (numRead <= 0) + throw new EndOfStreamException(); + + buffer[0] = (byte)_lookAhead; + _lookAhead = RequireByte(); + + return numRead + 1; + } +#endif + + public override int ReadByte() { if (_eofOn00 && _lookAhead <= 0) { diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs index 1c5ebd7c5..4fbb8baae 100644 --- a/crypto/src/bcpg/ArmoredInputStream.cs +++ b/crypto/src/bcpg/ArmoredInputStream.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -330,6 +331,26 @@ namespace Org.BouncyCastle.Bcpg return pos; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + /* + * TODO Currently can't return partial data when exception thrown (breaking test case), so we don't inherit + * the base class implementation. Probably the reason is that throws don't mark this instance as 'failed'. + */ + int pos = 0; + while (pos < buffer.Length) + { + int b = ReadByte(); + if (b < 0) + break; + + buffer[pos++] = (byte)b; + } + return pos; + } +#endif + public override int ReadByte() { if (start) diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs index 7a19a90dd..3b6f61bbc 100644 --- a/crypto/src/bcpg/BcpgInputStream.cs +++ b/crypto/src/bcpg/BcpgInputStream.cs @@ -57,6 +57,21 @@ namespace Org.BouncyCastle.Bcpg return 1; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + if (!next) + return m_in.Read(buffer); + + if (nextB < 0) + return 0; + + buffer[0] = (byte)nextB; + next = false; + return 1; + } +#endif + public byte[] ReadAll() { return Streams.ReadAll(this); @@ -312,9 +327,8 @@ namespace Org.BouncyCastle.Bcpg int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; int len = m_in.Read(buffer, offset, readLen); if (len < 1) - { throw new EndOfStreamException("Premature end of stream in PartialInputStream"); - } + dataLength -= len; return len; } @@ -324,6 +338,29 @@ namespace Org.BouncyCastle.Bcpg return 0; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + do + { + if (dataLength != 0) + { + int count = buffer.Length; + int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; + int len = m_in.Read(buffer[..readLen]); + if (len < 1) + throw new EndOfStreamException("Premature end of stream in PartialInputStream"); + + dataLength -= len; + return len; + } + } + while (partial && ReadPartialDataLength() >= 0); + + return 0; + } +#endif + private int ReadPartialDataLength() { int l = m_in.ReadByte(); diff --git a/crypto/src/bcpg/BcpgOutputStream.cs b/crypto/src/bcpg/BcpgOutputStream.cs index fbdd75bff..690686d88 100644 --- a/crypto/src/bcpg/BcpgOutputStream.cs +++ b/crypto/src/bcpg/BcpgOutputStream.cs @@ -164,7 +164,7 @@ namespace Org.BouncyCastle.Bcpg if (partialBuffer != null) { - PartialFlush(true); + PartialFlushLast(); partialBuffer = null; } @@ -215,19 +215,26 @@ namespace Org.BouncyCastle.Bcpg } } - private void PartialFlush(bool isLast) + private void PartialFlush() { - if (isLast) - { - WriteNewPacketLength(partialOffset); - outStr.Write(partialBuffer, 0, partialOffset); - } - else - { - outStr.WriteByte((byte)(0xE0 | partialPower)); - outStr.Write(partialBuffer, 0, partialBufferLength); - } + outStr.WriteByte((byte)(0xE0 | partialPower)); + outStr.Write(partialBuffer, 0, partialBufferLength); + partialOffset = 0; + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void PartialFlush(ref ReadOnlySpan buffer) + { + outStr.WriteByte((byte)(0xE0 | partialPower)); + outStr.Write(buffer[..partialBufferLength]); + buffer = buffer[partialBufferLength..]; + } +#endif + private void PartialFlushLast() + { + WriteNewPacketLength(partialOffset); + outStr.Write(partialBuffer, 0, partialOffset); partialOffset = 0; } @@ -235,40 +242,71 @@ namespace Org.BouncyCastle.Bcpg { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + PartialWrite(buffer.AsSpan(offset, count)); +#else if (partialOffset == partialBufferLength) { - PartialFlush(false); + PartialFlush(); } if (count <= (partialBufferLength - partialOffset)) { Array.Copy(buffer, offset, partialBuffer, partialOffset, count); partialOffset += count; + return; } - else + + int diff = partialBufferLength - partialOffset; + Array.Copy(buffer, offset, partialBuffer, partialOffset, diff); + offset += diff; + count -= diff; + PartialFlush(); + while (count > partialBufferLength) { - int diff = partialBufferLength - partialOffset; - Array.Copy(buffer, offset, partialBuffer, partialOffset, diff); - offset += diff; - count -= diff; - PartialFlush(false); - while (count > partialBufferLength) - { - Array.Copy(buffer, offset, partialBuffer, 0, partialBufferLength); - offset += partialBufferLength; - count -= partialBufferLength; - PartialFlush(false); - } - Array.Copy(buffer, offset, partialBuffer, 0, count); - partialOffset += count; + Array.Copy(buffer, offset, partialBuffer, 0, partialBufferLength); + offset += partialBufferLength; + count -= partialBufferLength; + PartialFlush(); } + Array.Copy(buffer, offset, partialBuffer, 0, count); + partialOffset = count; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void PartialWrite(ReadOnlySpan buffer) + { + if (partialOffset == partialBufferLength) + { + PartialFlush(); + } + + if (buffer.Length <= (partialBufferLength - partialOffset)) + { + buffer.CopyTo(partialBuffer.AsSpan(partialOffset)); + partialOffset += buffer.Length; + return; + } + + int diff = partialBufferLength - partialOffset; + buffer[..diff].CopyTo(partialBuffer.AsSpan(partialOffset)); + buffer = buffer[diff..]; + PartialFlush(); + while (buffer.Length > partialBufferLength) + { + PartialFlush(ref buffer); + } + buffer.CopyTo(partialBuffer); + partialOffset = buffer.Length; + } +#endif + private void PartialWriteByte(byte value) { if (partialOffset == partialBufferLength) { - PartialFlush(false); + PartialFlush(); } partialBuffer[partialOffset++] = value; @@ -286,6 +324,20 @@ namespace Org.BouncyCastle.Bcpg } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + if (partialBuffer != null) + { + PartialWrite(buffer); + } + else + { + outStr.Write(buffer); + } + } +#endif + public override void WriteByte(byte value) { if (partialBuffer != null) @@ -370,7 +422,7 @@ namespace Org.BouncyCastle.Bcpg { if (partialBuffer != null) { - PartialFlush(true); + PartialFlushLast(); Array.Clear(partialBuffer, 0, partialBuffer.Length); partialBuffer = null; } diff --git a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs index b2c5cac28..6348431a2 100644 --- a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs @@ -237,7 +237,14 @@ namespace Org.BouncyCastle.Cms macStream.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + macStream.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { macStream.WriteByte(value); } diff --git a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs index 1594500cd..3669c0b3a 100644 --- a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; @@ -118,7 +119,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs index 6a362e13f..ad356a208 100644 --- a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs @@ -240,7 +240,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs index f934b9259..3f2da5f7e 100644 --- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs @@ -783,7 +783,14 @@ namespace Org.BouncyCastle.Cms _out.Write(buffer, offset, count); } - public override void WriteByte(byte value) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + _out.Write(buffer); + } +#endif + + public override void WriteByte(byte value) { _out.WriteByte(value); } diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs index d4ca62256..7a66f0c74 100644 --- a/crypto/src/cms/CMSTypedStream.cs +++ b/crypto/src/cms/CMSTypedStream.cs @@ -59,13 +59,6 @@ namespace Org.BouncyCastle.Cms { } -#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public override void CopyTo(Stream destination, int bufferSize) - { - s.CopyTo(destination, bufferSize); - } -#endif - public override int Read(byte[] buf, int off, int len) { return Streams.ReadFully(s, buf, off, len); diff --git a/crypto/src/openpgp/PgpEncryptedData.cs b/crypto/src/openpgp/PgpEncryptedData.cs index 5cdc0d533..bad4cb8cd 100644 --- a/crypto/src/openpgp/PgpEncryptedData.cs +++ b/crypto/src/openpgp/PgpEncryptedData.cs @@ -54,6 +54,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { Streams.ValidateBufferArguments(buffer, offset, count); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return Read(buffer.AsSpan(offset, count)); +#else int avail = bufEnd - bufStart; int pos = offset; @@ -73,8 +76,34 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp bufStart += count; return pos + count - offset; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + int avail = bufEnd - bufStart; + + int pos = 0, count = buffer.Length; + while (count > avail) + { + lookAhead.AsSpan(bufStart, avail).CopyTo(buffer[pos..]); + + bufStart += avail; + pos += avail; + count -= avail; + + if ((avail = FillBuffer()) < 1) + return pos; + } + + lookAhead.AsSpan(bufStart, count).CopyTo(buffer[pos..]); + bufStart += count; + + return pos + count; + } +#endif + public override int ReadByte() { if (bufStart < bufEnd) diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs index c54ee0b3b..6f96dc9b8 100644 --- a/crypto/src/openpgp/WrappedGeneratorStream.cs +++ b/crypto/src/openpgp/WrappedGeneratorStream.cs @@ -13,10 +13,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp internal WrappedGeneratorStream(IStreamGenerator generator, Stream s) : base(s) { - if (generator == null) - throw new ArgumentNullException(nameof(generator)); - - m_generator = generator; + m_generator = generator ?? throw new ArgumentNullException(nameof(generator)); } protected override void Dispose(bool disposing) diff --git a/crypto/src/tls/CombinedHash.cs b/crypto/src/tls/CombinedHash.cs index 71151d2a5..360b9d426 100644 --- a/crypto/src/tls/CombinedHash.cs +++ b/crypto/src/tls/CombinedHash.cs @@ -43,6 +43,14 @@ namespace Org.BouncyCastle.Tls m_sha1.Update(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan input) + { + m_md5.Update(input); + m_sha1.Update(input); + } +#endif + public virtual byte[] CalculateHash() { if (null != m_context && TlsUtilities.IsSsl(m_context)) diff --git a/crypto/src/tls/DeferredHash.cs b/crypto/src/tls/DeferredHash.cs index 82f7899a5..e6397ab1e 100644 --- a/crypto/src/tls/DeferredHash.cs +++ b/crypto/src/tls/DeferredHash.cs @@ -176,6 +176,22 @@ namespace Org.BouncyCastle.Tls } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan input) + { + if (m_buf != null) + { + m_buf.Write(input); + return; + } + + foreach (TlsHash hash in m_hashes.Values) + { + hash.Update(input); + } + } +#endif + public byte[] CalculateHash() { throw new InvalidOperationException("Use 'ForkPrfHash' to get a definite hash"); diff --git a/crypto/src/tls/crypto/TlsHash.cs b/crypto/src/tls/crypto/TlsHash.cs index 4732fc280..6fbaeceb9 100644 --- a/crypto/src/tls/crypto/TlsHash.cs +++ b/crypto/src/tls/crypto/TlsHash.cs @@ -11,6 +11,10 @@ namespace Org.BouncyCastle.Tls.Crypto /// the length of the input data. void Update(byte[] input, int inOff, int length); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + void Update(ReadOnlySpan input); +#endif + /// Return calculated hash for any input passed in. /// the hash value. byte[] CalculateHash(); diff --git a/crypto/src/tls/crypto/TlsHashSink.cs b/crypto/src/tls/crypto/TlsHashSink.cs index a1681b0c8..3401eb60e 100644 --- a/crypto/src/tls/crypto/TlsHashSink.cs +++ b/crypto/src/tls/crypto/TlsHashSink.cs @@ -29,6 +29,16 @@ namespace Org.BouncyCastle.Tls.Crypto } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + if (!buffer.IsEmpty) + { + m_hash.Update(buffer); + } + } +#endif + public override void WriteByte(byte value) { m_hash.Update(new byte[]{ value }, 0, 1); diff --git a/crypto/src/tls/crypto/TlsMac.cs b/crypto/src/tls/crypto/TlsMac.cs index a898a9bcc..511e29d10 100644 --- a/crypto/src/tls/crypto/TlsMac.cs +++ b/crypto/src/tls/crypto/TlsMac.cs @@ -21,6 +21,10 @@ namespace Org.BouncyCastle.Tls.Crypto /// the length of the input data. void Update(byte[] input, int inOff, int length); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + void Update(ReadOnlySpan input); +#endif + /// Return calculated MAC for any input passed in. /// the MAC value. byte[] CalculateMac(); diff --git a/crypto/src/tls/crypto/TlsMacSink.cs b/crypto/src/tls/crypto/TlsMacSink.cs index e7d5c70d7..fbb2e5893 100644 --- a/crypto/src/tls/crypto/TlsMacSink.cs +++ b/crypto/src/tls/crypto/TlsMacSink.cs @@ -29,6 +29,16 @@ namespace Org.BouncyCastle.Tls.Crypto } } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + if (!buffer.IsEmpty) + { + m_mac.Update(buffer); + } + } +#endif + public override void WriteByte(byte value) { m_mac.Update(new byte[]{ value }, 0, 1); diff --git a/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs b/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs index f26a50d46..a0378e334 100644 --- a/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs +++ b/crypto/src/tls/crypto/impl/bc/BcSsl3Hmac.cs @@ -66,6 +66,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_digest.BlockUpdate(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan input) + { + m_digest.BlockUpdate(input); + } +#endif + public virtual byte[] CalculateMac() { byte[] result = new byte[m_digest.GetDigestSize()]; diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs b/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs index 0b35831f3..0ad2576cb 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsHash.cs @@ -28,6 +28,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_digest.BlockUpdate(data, offSet, length); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan input) + { + m_digest.BlockUpdate(input); + } +#endif + public byte[] CalculateHash() { byte[] rv = new byte[m_digest.GetDigestSize()]; diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs b/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs index 7a2318a31..dbe7f4c69 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsHmac.cs @@ -32,6 +32,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC m_hmac.BlockUpdate(input, inOff, length); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Update(ReadOnlySpan input) + { + m_hmac.BlockUpdate(input); + } +#endif + public byte[] CalculateMac() { byte[] rv = new byte[m_hmac.GetMacSize()]; diff --git a/crypto/src/util/io/BaseInputStream.cs b/crypto/src/util/io/BaseInputStream.cs index ebe256632..eaaf9556d 100644 --- a/crypto/src/util/io/BaseInputStream.cs +++ b/crypto/src/util/io/BaseInputStream.cs @@ -45,5 +45,9 @@ namespace Org.BouncyCastle.Utilities.IO public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) { throw new NotSupportedException(); } +#endif } } diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs index dad9b19a4..0fc8e9681 100644 --- a/crypto/src/util/io/BaseOutputStream.cs +++ b/crypto/src/util/io/BaseOutputStream.cs @@ -21,6 +21,9 @@ namespace Org.BouncyCastle.Utilities.IO set { throw new NotSupportedException(); } } public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public sealed override int Read(Span buffer) { throw new NotSupportedException(); } +#endif public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } diff --git a/crypto/src/util/io/FilterStream.cs b/crypto/src/util/io/FilterStream.cs index d9bcbb8ef..38077edd2 100644 --- a/crypto/src/util/io/FilterStream.cs +++ b/crypto/src/util/io/FilterStream.cs @@ -10,10 +10,7 @@ namespace Org.BouncyCastle.Utilities.IO public FilterStream(Stream s) { - if (s == null) - throw new ArgumentNullException(nameof(s)); - - this.s = s; + this.s = s ?? throw new ArgumentNullException(nameof(s)); } public override bool CanRead { @@ -27,6 +24,12 @@ namespace Org.BouncyCastle.Utilities.IO { get { return s.CanWrite; } } +#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void CopyTo(Stream destination, int bufferSize) + { + s.CopyTo(destination, bufferSize); + } +#endif public override void Flush() { s.Flush(); @@ -44,6 +47,12 @@ namespace Org.BouncyCastle.Utilities.IO { return s.Read(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override int Read(Span buffer) + { + return s.Read(buffer); + } +#endif public override int ReadByte() { return s.ReadByte(); @@ -60,6 +69,12 @@ namespace Org.BouncyCastle.Utilities.IO { s.Write(buffer, offset, count); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public override void Write(ReadOnlySpan buffer) + { + s.Write(buffer); + } +#endif public override void WriteByte(byte value) { s.WriteByte(value); -- cgit 1.4.1