public unsafe void EncryptSessionKey(ref WritableBuffer writer, Span <byte> ticketContent)
        {
            var tagLength = 16;
            var key       = _keys.Take();

            try
            {
                var contentLength = ticketContent.Length + tagLength + sizeof(long) + sizeof(Guid);
                var nonce         = System.Threading.Interlocked.Increment(ref _nounceCounter);
                writer.WriteBigEndian((ushort)contentLength);
                writer.Ensure(contentLength);

                key.IV.Slice(4).Span.Write(nonce);
                key.Init(KeyMode.Encryption);

                writer.WriteBigEndian(_keyGuid);
                writer.WriteBigEndian(_nounceCounter);

                var amountWritten = key.Finish(ticketContent, writer.Buffer.Span);
                writer.Advance(amountWritten);
                key.GetTag(writer.Buffer.Span.Slice(0, tagLength));
                writer.Advance(tagLength);
            }
            finally
            {
                _keys.Add(key);
            }
        }
예제 #2
0
        public unsafe void Encrypt(ref WritableBuffer buffer, ReadableBuffer plainText, RecordType recordType)
        {
            int      outLength;
            GCHandle inHandle, outHandle;

            ThrowOnError(EVP_CipherInit_ex(_ctx, _cipherType, IntPtr.Zero, (void *)_keyPointer, (void *)_ivPointer, (int)KeyMode.Encryption));
            foreach (var b in plainText)
            {
                if (b.Length == 0)
                {
                    continue;
                }
                buffer.Ensure(b.Length);
                var inPtr  = b.GetPointer(out inHandle);
                var outPtr = buffer.Memory.GetPointer(out outHandle);
                try
                {
                    outLength = buffer.Memory.Length;
                    ThrowOnError(EVP_CipherUpdate(_ctx, outPtr, ref outLength, inPtr, b.Length));
                    buffer.Advance(outLength);
                }
                finally
                {
                    if (inHandle.IsAllocated)
                    {
                        inHandle.Free();
                    }
                    if (outHandle.IsAllocated)
                    {
                        outHandle.Free();
                    }
                }
            }
            buffer.Ensure(Overhead + sizeof(RecordType));
            var writePtr = buffer.Memory.GetPointer(out outHandle);

            outLength = buffer.Memory.Length;
            ThrowOnError(EVP_CipherUpdate(_ctx, writePtr, ref outLength, &recordType, sizeof(RecordType)));
            buffer.Advance(outLength);
            if (_paddingSize > 0)
            {
                outLength = _paddingSize;
                writePtr  = buffer.Memory.GetPointer(out outHandle);
                ThrowOnError(EVP_CipherUpdate(_ctx, writePtr, ref outLength, (byte *)s_zeroBuffer, _paddingSize));
                buffer.Advance(outLength);
            }
            writePtr  = buffer.Memory.GetPointer(out outHandle);
            outLength = 0;
            ThrowOnError(EVP_CipherFinal_ex(_ctx, null, ref outLength));
            ThrowOnError(EVP_CIPHER_CTX_ctrl(_ctx, EVP_CIPHER_CTRL.EVP_CTRL_GCM_GET_TAG, _overhead, writePtr));
            buffer.Advance(_overhead);
            IncrementSequence();
        }
예제 #3
0
        private static void WriteAsciiString(ref WritableBuffer buffer, ReadOnlySpan <char> value)
        {
            if (value == null || value.Length == 0)
            {
                return;
            }

            while (value.Length != 0)
            {
                buffer.Ensure();

                var span         = buffer.Buffer.Span;
                int bytesToWrite = Math.Min(value.Length, span.Length);

                // todo: Vector.Narrow

                for (int i = 0; i < bytesToWrite; i++)
                {
                    span[i] = (byte)value[i];
                }

                buffer.Advance(bytesToWrite);
                buffer.Commit();
                value = value.Slice(bytesToWrite);
            }
        }
예제 #4
0
        protected override void WriteRecords(ref ReadableBuffer buffer, ref WritableBuffer writer, RecordType recordType)
        {
            ReadableBuffer append;

            while (buffer.Length > 0)
            {
                append = buffer.Slice(0, Math.Min(_maxMessageSize, buffer.Length));
                buffer = buffer.Slice(append.End);
                var recordHeader = new RecordHeader()
                {
                    RecordType = recordType,
                    Length     = (ushort)append.Length,
                    Version    = _recordVersion
                };
                writer.Ensure(_minimumMessageSize);
                if (_connection?.WriteKey != null)
                {
                    recordHeader.Length += (ushort)(8 + _connection.WriteKey.Overhead);
                }
                writer.Buffer.Span.Write(recordHeader);
                writer.Advance(_minimumMessageSize);
                if (_connection?.WriteKey != null)
                {
                    _connection.WriteKey.Encrypt(ref writer, append, recordType, _recordVersion);
                }
                else
                {
                    writer.Append(append);
                }
            }
        }
예제 #5
0
        public void ByteByByteTest()
        {
            WritableBuffer writableBuffer = default;

            for (int i = 1; i <= 1024 * 1024; i++)
            {
                writableBuffer = _pipe.Writer.Alloc(100);
                writableBuffer.Advance(1);
                writableBuffer.Commit();

                Assert.Equal(i, _pipe.Length);
            }

            writableBuffer.FlushAsync();

            for (int i = 1024 * 1024 - 1; i >= 0; i--)
            {
                var result   = _pipe.Reader.ReadAsync().GetResult();
                var consumed = result.Buffer.Slice(1).Start;

                Assert.Equal(i + 1, result.Buffer.Length);

                _pipe.Reader.Advance(consumed, consumed);

                Assert.Equal(i, _pipe.Length);
            }
        }
예제 #6
0
        private static void PingPayloadWriter(WritableBuffer output, Span <byte> maskingKey, int payloadLength, DateTime timestamp)
        {
            var payload = output.Memory.Slice(0, payloadLength);

            // TODO: Don't put this string on the heap? Is there a way to do that without re-implementing ToString?
            // Ideally we'd like to render the string directly to the output buffer.
            var str = timestamp.ToString("O", CultureInfo.InvariantCulture);

            ArraySegment <byte> buffer;

            if (payload.TryGetArray(out buffer))
            {
                // Fast path - Write the encoded bytes directly out.
                Encoding.UTF8.GetBytes(str, 0, str.Length, buffer.Array, buffer.Offset);
            }
            else
            {
                // TODO: Could use TryGetPointer, GetBytes does take a byte*, but it seems like just waiting until we have a version that uses Span is best.
                // Slow path - Allocate a heap buffer for the encoded bytes before writing them out.
                payload.Span.Set(Encoding.UTF8.GetBytes(str));
            }

            if (maskingKey.Length > 0)
            {
                MaskingUtilities.ApplyMask(payload.Span, maskingKey);
            }

            output.Advance(payloadLength);
        }
예제 #7
0
        public unsafe void WritePublicKey(ref WritableBuffer keyBuffer)
        {
            GenerateECKeySet();
            var    key    = EVP_PKEY_get0_EC_KEY(_eKey);
            var    pubKey = EC_KEY_get0_public_key(key);
            var    group  = EC_KEY_get0_group(key);
            IntPtr size   = EC_POINT_point2oct(group, pubKey, EC_POINT_CONVERSION.POINT_CONVERSION_UNCOMPRESSED, null, IntPtr.Zero, IntPtr.Zero);
            var    s      = (ushort)size.ToInt32();

            keyBuffer.Ensure(s);
            GCHandle handle;
            var      ptr = keyBuffer.Memory.GetPointer(out handle);

            try
            {
                size = EC_POINT_point2oct(group, pubKey, EC_POINT_CONVERSION.POINT_CONVERSION_UNCOMPRESSED, ptr, size, IntPtr.Zero);
                keyBuffer.Advance(s);
            }
            finally
            {
                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }
        }
예제 #8
0
        internal static void WriteFrameHeader(ref WritableBuffer output, WebSocketsFrame.FrameFlags flags, WebSocketsFrame.OpCodes opCode, int payloadLength, int mask)
        {
            output.Ensure(MaxHeaderLength);

            int index = 0;
            var span  = output.Buffer.Span;

            span[index++] = (byte)(((int)flags & 240) | ((int)opCode & 15));
            if (payloadLength > ushort.MaxValue)
            { // write as a 64-bit length
                span[index++] = (byte)((mask != 0 ? 128 : 0) | 127);
                span.Slice(index).Write((uint)0);
                span.Slice(index + 4).Write(ToNetworkByteOrder((uint)payloadLength));
                index += 8;
            }
            else if (payloadLength > 125)
            { // write as a 16-bit length
                span[index++] = (byte)((mask != 0 ? 128 : 0) | 126);
                span.Slice(index).Write(ToNetworkByteOrder((ushort)payloadLength));
                index += 2;
            }
            else
            { // write in the header
                span[index++] = (byte)((mask != 0 ? 128 : 0) | payloadLength);
            }
            if (mask != 0)
            {
                span.Slice(index).Write(mask);
                index += 4;
            }
            output.Advance(index);
        }
예제 #9
0
        public static WritableBuffer CreateNewSessionKey(WritableBuffer buffer, IConnectionStateTls13 state)
        {
            var lifetime = TicketLifeTimeInHours * 60 * 60;

            buffer.WriteBigEndian((uint)lifetime);
            buffer.Ensure(4);
            state.CryptoProvider.FillWithRandom(buffer.Memory.Slice(0, 4));
            buffer.Advance(4);

            BufferExtensions.WriteVector <ushort>(ref buffer, (writer, conn) =>
            {
                state.ResumptionProvider.GenerateSessionTicket(ref writer, conn);
                return(writer);
            }, state);

            BufferExtensions.WriteVector <ushort>(ref buffer, (writer, conn) =>
            {
                writer.WriteBigEndian(ExtensionType.ticket_early_data_info);
                writer.WriteBigEndian <ushort>(sizeof(uint));
                uint maxData = 1024 * 2;
                writer.WriteBigEndian(maxData);
                return(writer);
            }, state);
            return(buffer);
        }
예제 #10
0
        // review: make public?
        private static unsafe void WriteString(this WritableBuffer buffer, string value, Encoding encoding)
        {
            int bytesPerChar = encoding.GetMaxByteCount(1);

            fixed(char *s = value)
            {
                int remainingChars = value.Length, charOffset = 0;

                while (remainingChars != 0)
                {
                    buffer.Ensure(bytesPerChar);

                    var memory         = buffer.Memory;
                    var charsThisBatch = Math.Min(remainingChars, memory.Length / bytesPerChar);
                    int bytesWritten   = 0;

                    void *pointer;
                    ArraySegment <byte> data;
                    if (memory.TryGetPointer(out pointer))
                    {
                        bytesWritten = encoding.GetBytes(s + charOffset, charsThisBatch,
                                                         (byte *)pointer, memory.Length);
                    }
                    else if (memory.TryGetArray(out data))
                    {
                        bytesWritten = encoding.GetBytes(value, charOffset, charsThisBatch, data.Array, data.Offset);
                    }

                    charOffset     += charsThisBatch;
                    remainingChars -= charsThisBatch;
                    buffer.Advance(bytesWritten);
                }
            }
        }
예제 #11
0
 public static void WriteCertificateEntry(ref WritableBuffer writer, byte[] certificate)
 {
     writer.Ensure(3);
     writer.Memory.Write24BitNumber(certificate.Length);
     writer.Advance(3);
     writer.Write(certificate);
 }
예제 #12
0
 private unsafe static void FillBuffer(ref WritableBuffer wb, int count)
 {
     for (int i = 0; i < count; i++)
     {
         wb.Ensure(4);
         void *pointer;
         Assert.True(wb.Buffer.TryGetPointer(out pointer));
         *(int *)pointer = i;
         wb.Advance(4);
     }
 }
예제 #13
0
        private void OnRead(UvStreamHandle handle, int status)
        {
            if (status == 0)
            {
                // A zero status does not indicate an error or connection end. It indicates
                // there is no data to be read right now.
                // See the note at http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb.
                // We need to clean up whatever was allocated by OnAlloc.
                _inputBuffer.FlushAsync();
                return;
            }

            var normalRead = status > 0;
            var normalDone = status == EOF;
            var errorDone  = !(normalDone || normalRead);
            var readCount  = normalRead ? status : 0;

            if (!normalRead)
            {
                handle.ReadStop();
            }

            IOException error = null;

            if (errorDone)
            {
                Exception uvError;
                handle.Libuv.Check(status, out uvError);
                error = new IOException(uvError.Message, uvError);

                // REVIEW: Should we treat ECONNRESET as an error?
                // Ignore the error for now
                _input.CompleteWriter();
            }
            else if (readCount == 0 || _input.Writing.IsCompleted)
            {
                _input.CompleteWriter();
            }
            else
            {
                _inputBuffer.Advance(readCount);

                var task = _inputBuffer.FlushAsync();

                if (!task.IsCompleted)
                {
                    // If there's back pressure
                    handle.ReadStop();

                    // Resume reading when task continues
                    task.ContinueWith((t, state) => ((UvTcpConnection)state).StartReading(), this);
                }
            }
        }
예제 #14
0
        public static void WriteVector24Bit(ref WritableBuffer buffer, Func <WritableBuffer, IConnectionStateTls13, WritableBuffer> writeContent, IConnectionStateTls13 state)
        {
            buffer.Ensure(3);
            var bookmark = buffer.Memory;

            buffer.Advance(3);
            int currentSize = buffer.BytesWritten;

            buffer      = writeContent(buffer, state);
            currentSize = buffer.BytesWritten - currentSize;
            bookmark.Write24BitNumber(currentSize);
        }
예제 #15
0
파일: Hello.cs 프로젝트: vcsjones/Leto
        public static WritableBuffer SendServerHello13(WritableBuffer buffer, IConnectionStateTls13 connectionState)
        {
            buffer.Ensure(RandomLength + sizeof(ushort));
            buffer.WriteBigEndian(connectionState.Version);
            var memoryToFill = buffer.Memory.Slice(0, RandomLength);

            connectionState.CryptoProvider.FillWithRandom(memoryToFill);
            buffer.Advance(RandomLength);
            buffer.WriteBigEndian(connectionState.CipherSuite.CipherCode);
            BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, connectionState);
            return(buffer);
        }
예제 #16
0
        public void ReceiveBeginComplete(uint bytesTransferred)
        {
            if (bytesTransferred == 0 || _input.Writing.IsCompleted)
            {
                _input.CompleteWriter();
            }
            else
            {
                _buffer.Advance((int)bytesTransferred);
                _buffer.Commit();

                ProcessReceives();
            }
        }
예제 #17
0
        public override void Encrypt(ref WritableBuffer writer, ReadableBuffer plainText, RecordType recordType, TlsVersion tlsVersion)
        {
            _key.IV.Span.Slice(4).WriteBigEndian(_sequenceNumber);
            _key.Init(KeyMode.Encryption);
            var additionalInfo = new AdditionalInfo()
            {
                SequenceNumber  = _sequenceNumber,
                RecordType      = recordType,
                TlsVersion      = tlsVersion,
                PlainTextLength = (ushort)plainText.Length
            };

            _key.AddAdditionalInfo(ref additionalInfo);
            writer.WriteBigEndian(_sequenceNumber);
            var totalBytes = plainText.Length;

            foreach (var b in plainText)
            {
                if (b.Length == 0)
                {
                    continue;
                }
                totalBytes -= b.Length;
                writer.Ensure(b.Length);
                int bytesWritten;
                if (totalBytes == 0)
                {
                    bytesWritten = _key.Finish(b.Span, writer.Buffer.Span);
                    writer.Advance(bytesWritten);
                    break;
                }
                bytesWritten = _key.Update(b.Span, writer.Buffer.Span);
                writer.Advance(bytesWritten);
            }
            IncrementSequence();
            WriteTag(ref writer);
        }
예제 #18
0
        /// <summary>
        /// Writes the source <see cref="Span{Byte}"/> to the <see cref="WritableBuffer"/>.
        /// </summary>
        /// <param name="buffer">The <see cref="WritableBuffer"/></param>
        /// <param name="source">The <see cref="Span{Byte}"/> to write</param>
        public static void Write(this WritableBuffer buffer, ReadOnlySpan <byte> source)
        {
            if (buffer.Memory.IsEmpty)
            {
                buffer.Ensure();
            }

            // Fast path, try copying to the available memory directly
            if (source.Length <= buffer.Memory.Length)
            {
                source.CopyTo(buffer.Memory.Span);
                buffer.Advance(source.Length);
                return;
            }

            var remaining = source.Length;
            var offset    = 0;

            while (remaining > 0)
            {
                var writable = Math.Min(remaining, buffer.Memory.Length);

                buffer.Ensure(writable);

                if (writable == 0)
                {
                    continue;
                }

                source.Slice(offset, writable).CopyTo(buffer.Memory.Span);

                remaining -= writable;
                offset    += writable;

                buffer.Advance(writable);
            }
        }
예제 #19
0
파일: Hello.cs 프로젝트: vcsjones/Leto
 public static WritableBuffer WriteClientHello(WritableBuffer buffer, IConnectionStateTls13 connectionState)
 {
     buffer.WriteBigEndian <ushort>(0x0303);
     buffer.Ensure(RandomLength);
     connectionState.CryptoProvider.FillWithRandom(buffer.Memory.Slice(0, RandomLength));
     buffer.Advance(RandomLength);
     //legacy sessionid
     buffer.WriteBigEndian((byte)0);
     connectionState.CryptoProvider.WriteCipherSuites(ref buffer);
     //legacy compression
     buffer.WriteBigEndian((byte)1);
     buffer.WriteBigEndian((byte)0);
     connectionState.KeyShare = connectionState.CryptoProvider.GetDefaultKeyShare();
     BufferExtensions.WriteVector <ushort>(ref buffer, ExtensionsWrite.WriteExtensionList, connectionState);
     return(buffer);
 }
        internal static unsafe void Encrypt <T>(this T context, WritableBuffer outBuffer, ReadableBuffer buffer) where T : ISecureContext
        {
            outBuffer.Ensure(context.TrailerSize + context.HeaderSize + buffer.Length);
            void *outBufferPointer;

            outBuffer.Memory.TryGetPointer(out outBufferPointer);

            buffer.CopyTo(outBuffer.Memory.Slice(context.HeaderSize, buffer.Length));

            var securityBuff = stackalloc SecurityBuffer[4];
            SecurityBufferDescriptor sdcInOut = new SecurityBufferDescriptor(4);

            securityBuff[0].size         = context.HeaderSize;
            securityBuff[0].type         = SecurityBufferType.Header;
            securityBuff[0].tokenPointer = outBufferPointer;

            securityBuff[1].size         = buffer.Length;
            securityBuff[1].type         = SecurityBufferType.Data;
            securityBuff[1].tokenPointer = (byte *)outBufferPointer + context.HeaderSize;

            securityBuff[2].size         = context.TrailerSize;
            securityBuff[2].type         = SecurityBufferType.Trailer;
            securityBuff[2].tokenPointer = (byte *)outBufferPointer + context.HeaderSize + buffer.Length;

            securityBuff[3].size         = 0;
            securityBuff[3].tokenPointer = null;
            securityBuff[3].type         = SecurityBufferType.Empty;

            sdcInOut.UnmanagedPointer = securityBuff;

            var handle = context.ContextHandle;
            var result = (SecurityStatus)InteropSspi.EncryptMessage(ref handle, 0, sdcInOut, 0);

            if (result == 0)
            {
                outBuffer.Advance(context.HeaderSize + context.TrailerSize + buffer.Length);
            }
            else
            {
                //Zero out the output buffer before throwing the exception to stop any data being sent in the clear
                //By a misbehaving underlying channel
                Span <byte> memoryToClear = new Span <byte>(outBufferPointer, context.HeaderSize + context.TrailerSize + buffer.Length);
                byte *      empty         = stackalloc byte[context.HeaderSize + context.TrailerSize + buffer.Length];
                memoryToClear.Set(empty, context.HeaderSize + context.TrailerSize + buffer.Length);
                throw new InvalidOperationException($"There was an issue encrypting the data {result}");
            }
        }
예제 #21
0
        public void WriteBigEndian <T>(T value) where T : struct
        {
            var size = Unsafe.SizeOf <T>();

            if (_bytesRemaining < size)
            {
                _innerBuffer.Ensure(size);
                _bytesRemaining = _innerBuffer.Buffer.Length;
            }
            var s = _innerBuffer.Buffer.Span;

            size = s.WriteBigEndian(value);
            _handshakeHash?.HashData(s.Slice(0, size));
            _innerBuffer.Advance(size);
            _bytesWritten   += size;
            _bytesRemaining -= size;
        }
예제 #22
0
        private static void WriteUtf8String(ref WritableBuffer buffer, ReadOnlySpan <char> value)
        {
            if (value == null || value.Length == 0)
            {
                return;
            }

            var encoder = TextEncoder.Utf8;

            while (value.Length != 0)
            {
                buffer.Ensure(4); // be able to write at least one character (worst case)

                var span = buffer.Buffer.Span;
                encoder.TryEncode(value, span, out int charsConsumed, out int bytesWritten);
                buffer.Advance(bytesWritten);
                buffer.Commit();
                value = value.Slice(charsConsumed);
            }
        }
예제 #23
0
        public unsafe void EncryptWithAuthData(ref WritableBuffer buffer, RecordType recordType, ushort tlsVersion, int plaintextLength)
        {
            var additionalData = stackalloc byte[13];
            var additionalSpan = new Span <byte>(additionalData, 13);

            additionalSpan.Write64BitNumber(_sequenceNumber);
            additionalSpan = additionalSpan.Slice(8);
            additionalSpan.Write(recordType);
            additionalSpan = additionalSpan.Slice(1);
            additionalSpan.Write(tlsVersion);
            additionalSpan = additionalSpan.Slice(2);
            additionalSpan.Write16BitNumber((ushort)plaintextLength);

            var plainText = buffer.AsReadableBuffer();

            plainText = plainText.Slice(plainText.Length - plaintextLength);

            ThrowOnError(EVP_CipherInit_ex(_ctx, _cipherType, IntPtr.Zero, (byte *)_keyPointer, (void *)_ivPointer, (int)KeyMode.Encryption));
            int outSize = 0;

            ThrowOnError(EVP_CipherUpdate(_ctx, null, ref outSize, additionalData, 13));
            void *inPointer;

            foreach (var b in plainText)
            {
                if (b.Length == 0)
                {
                    continue;
                }
                b.TryGetPointer(out inPointer);
                outSize = b.Length;
                ThrowOnError(EVP_CipherUpdate(_ctx, inPointer, ref outSize, inPointer, outSize));
            }
            buffer.Ensure(_overhead);
            buffer.Memory.TryGetPointer(out inPointer);
            ThrowOnError(EVP_CipherFinal_ex(_ctx, null, ref outSize));
            ThrowOnError(EVP_CIPHER_CTX_ctrl(_ctx, EVP_CIPHER_CTRL.EVP_CTRL_GCM_GET_TAG, _overhead, inPointer));
            buffer.Advance(_overhead);
            _sequenceNumber++;
            IncrementSequence();
        }
예제 #24
0
        public override void Encrypt(ref WritableBuffer writer, Span <byte> plainText, RecordType recordType, TlsVersion tlsVersion)
        {
            _key.IV.Span.Slice(4).WriteBigEndian(_sequenceNumber);
            _key.Init(KeyMode.Encryption);
            var additionalInfo = new AdditionalInfo()
            {
                SequenceNumber  = _sequenceNumber,
                RecordType      = recordType,
                TlsVersion      = tlsVersion,
                PlainTextLength = (ushort)plainText.Length
            };

            _key.AddAdditionalInfo(ref additionalInfo);
            writer.WriteBigEndian(_sequenceNumber);
            writer.Ensure(plainText.Length);
            var bytesWritten = _key.Finish(plainText, writer.Buffer.Span);

            writer.Advance(bytesWritten);
            IncrementSequence();
            WriteTag(ref writer);
        }
예제 #25
0
        public unsafe void WritePublicKey(ref WritableBuffer keyBuffer)
        {
            if (!_publicPrivateKey.IsValid())
            {
                GenerateKeyset();
            }
            IntPtr ptr;
            var    buffSize = (int)ThrowOnError(EVP_PKEY_get1_tls_encodedpoint(_publicPrivateKey, out ptr));

            try
            {
                keyBuffer.Ensure(buffSize);
                var span = new Span <byte>((byte *)ptr, buffSize);
                span.CopyTo(keyBuffer.Memory.Span);
                keyBuffer.Advance(span.Length);
            }
            finally
            {
                CRYPTO_clear_free(ptr, (UIntPtr)buffSize, "ECFunctionInstance.cs", 97);
            }
        }
예제 #26
0
        public unsafe void WritePublicKey(ref WritableBuffer keyBuffer)
        {
            BIGNUM priv, pub;

            DH_get0_key(_localKey, out pub, out priv);
            keyBuffer.Ensure(_keyExchangeSize);
            GCHandle handle;
            void *   ptr = keyBuffer.Memory.GetPointer(out handle);

            try
            {
                var written = BN_bn2binpad(pub, ptr, _keyExchangeSize);
                keyBuffer.Advance(written);
            }
            finally
            {
                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }
        }
예제 #27
0
        // review: make public?
        private static unsafe void WriteString(this WritableBuffer buffer, string value, Encoding encoding)
        {
            int bytesPerChar = encoding.GetMaxByteCount(1);

            fixed(char *s = value)
            {
                int remainingChars = value.Length, charOffset = 0;

                while (remainingChars != 0)
                {
                    buffer.Ensure(bytesPerChar);

                    var memory         = buffer.Memory;
                    var charsThisBatch = Math.Min(remainingChars, memory.Length / bytesPerChar);

                    int bytesWritten = encoding.GetBytes(s + charOffset, charsThisBatch,
                                                         (byte *)memory.UnsafePointer, memory.Length);

                    charOffset     += charsThisBatch;
                    remainingChars -= charsThisBatch;
                    buffer.Advance(bytesWritten);
                }
            }
        }
예제 #28
0
        public unsafe int SignHash(IHashProvider provider, SignatureScheme scheme, ref WritableBuffer writer, byte *message, int messageLength)
        {
            var hash = provider.GetHashInstance(_hashType);

            hash.HashData(message, messageLength);

            var digest = new byte[hash.HashSize];

            fixed(byte *dPtr = digest)
            {
                hash.InterimHash(dPtr, digest.Length);
            }

            writer.Ensure(ECDSA_size(_ecKey));
            GCHandle handle;
            var      output = writer.Memory.GetPointer(out handle);

            try
            {
                fixed(byte *iPtr = digest)
                {
                    var sigSize = writer.Memory.Length;

                    ThrowOnError(ECDSA_sign(0, iPtr, digest.Length, output, ref sigSize, _ecKey));
                    writer.Advance(sigSize);
                    return(sigSize);
                }
            }
            finally
            {
                if (handle.IsAllocated)
                {
                    handle.Free();
                }
            }
        }
예제 #29
0
        private async Task ReceiveFromSocketAndPushToWriterAsync()
        {
            SocketAsyncEventArgs args = null;

            try
            {
                // wait for someone to be interested in data before we
                // start allocating buffers and probing the socket
                args = GetOrCreateSocketAsyncEventArgs();
                while (!_stopping)
                {
                    bool           haveWriteBuffer = false;
                    WritableBuffer buffer          = default(WritableBuffer);
                    var            initialSegment  = default(ArraySegment <byte>);

                    try
                    {
                        int bytesFromInitialDataBuffer = 0;

                        if (Socket.Available == 0)
                        {
                            // now, this gets a bit messy unfortunately, because support for the ideal option
                            // (zero-length reads) is platform dependent
                            switch (_bufferStyle)
                            {
                            case BufferStyle.Unknown:
                                try
                                {
                                    initialSegment = await ReceiveInitialDataUnknownStrategyAsync(args);
                                }
                                catch
                                {
                                    initialSegment = default(ArraySegment <byte>);
                                }
                                if (initialSegment.Array == null)
                                {
                                    continue;     // redo from start
                                }
                                break;

                            case BufferStyle.UseZeroLengthBuffer:
                                // if we already have a buffer, use that (but: zero count); otherwise use a shared
                                // zero-length; this avoids constantly changing the buffer that the args use, which
                                // avoids some overheads
                                args.SetBuffer(args.Buffer ?? _zeroLengthBuffer, 0, 0);

                                // await async for the io work to be completed
                                await Socket.ReceiveSignalAsync(args);

                                break;

                            case BufferStyle.UseSmallBuffer:
                                // We need  to do a speculative receive with a *cheap* buffer while we wait for input; it would be *nice* if
                                // we could do a zero-length receive, but this is not supported equally on all platforms (fine on Windows, but
                                // linux hates it). The key aim here is to make sure that we don't tie up an entire block from the memory pool
                                // waiting for input on a socket; fine for 1 socket, not so fine for 100,000 sockets

                                // do a short receive while we wait (async) for data
                                initialSegment = LeaseSmallBuffer();
                                args.SetBuffer(initialSegment.Array, initialSegment.Offset, initialSegment.Count);

                                // await async for the io work to be completed
                                await Socket.ReceiveSignalAsync(args);

                                break;
                            }
                            if (args.SocketError != SocketError.Success)
                            {
                                throw new SocketException((int)args.SocketError);
                            }

                            // note we can't check BytesTransferred <= 0, as we always
                            // expect 0; but if we returned, we expect data to be
                            // buffered *on the socket*, else EOF
                            if ((bytesFromInitialDataBuffer = args.BytesTransferred) <= 0)
                            {
                                if (ReferenceEquals(initialSegment.Array, _zeroLengthBuffer))
                                {
                                    // sentinel value that means we should just
                                    // consume sync (we expect there to be data)
                                    initialSegment = default(ArraySegment <byte>);
                                }
                                else
                                {
                                    // socket reported EOF
                                    RecycleSmallBuffer(ref initialSegment);
                                }
                                if (Socket.Available == 0)
                                {
                                    // yup, definitely an EOF
                                    break;
                                }
                            }
                        }

                        // note that we will try to coalesce things here to reduce the number of flushes; we
                        // certainly want to coalesce the initial buffer (from the speculative receive) with the initial
                        // data, but we probably don't want to buffer indefinitely; for now, it will buffer up to 4 pages
                        // before flushing (entirely arbitrarily) - might want to make this configurable later
                        buffer          = _input.Writer.Alloc(SmallBufferSize * 2);
                        haveWriteBuffer = true;

                        const int FlushInputEveryBytes = 4 * MemoryPool.MaxPooledBlockLength;

                        if (initialSegment.Array != null)
                        {
                            // need to account for anything that we got in the speculative receive
                            if (bytesFromInitialDataBuffer != 0)
                            {
                                buffer.Write(new Span <byte>(initialSegment.Array, initialSegment.Offset, bytesFromInitialDataBuffer));
                            }
                            // make the small buffer available to other consumers
                            RecycleSmallBuffer(ref initialSegment);
                        }

                        bool isEOF = false;
                        while (Socket.Available != 0 && buffer.BytesWritten < FlushInputEveryBytes)
                        {
                            buffer.Ensure(); // ask for *something*, then use whatever is available (usually much much more)
                            SetBuffer(buffer.Buffer, args);
                            // await async for the io work to be completed
                            await Socket.ReceiveSignalAsync(args);

                            // either way, need to validate
                            if (args.SocketError != SocketError.Success)
                            {
                                throw new SocketException((int)args.SocketError);
                            }
                            int len = args.BytesTransferred;
                            if (len <= 0)
                            {
                                // socket reported EOF
                                isEOF = true;
                                break;
                            }

                            // record what data we filled into the buffer
                            buffer.Advance(len);
                        }
                        if (isEOF)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        RecycleSmallBuffer(ref initialSegment);
                        if (haveWriteBuffer)
                        {
                            _stopping = (await buffer.FlushAsync()).IsCompleted;
                        }
                    }
                }
                _input.Writer.Complete();
            }
            catch (Exception ex)
            {
                // don't trust signal after an error; someone else could
                // still have it and invoke Set
                if (args != null)
                {
                    args.UserToken = null;
                }
                _input?.Writer.Complete(ex);
            }
            finally
            {
                try
                {
                    Socket.Shutdown(SocketShutdown.Receive);
                }
                catch { }

                RecycleSocketAsyncEventArgs(args);
            }
        }
예제 #30
0
 public void Advance(int bytes)
 {
     _writableBuffer.Advance(bytes);
 }