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(); }
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); } }
public unsafe static WritableBuffer SendKeyExchange(WritableBuffer buffer, IConnectionStateTls12 connectionState) { var messageLength = 4 + connectionState.KeyShare.KeyExchangeSize; buffer.Ensure(messageLength); var bookMark = buffer.Memory; buffer.WriteBigEndian(ECCurveType.named_curve); buffer.WriteBigEndian(connectionState.KeyShare.NamedGroup); buffer.WriteBigEndian((byte)connectionState.KeyShare.KeyExchangeSize); connectionState.KeyShare.WritePublicKey(ref buffer); buffer.WriteBigEndian(connectionState.SignatureScheme); BufferExtensions.WriteVector <ushort>(ref buffer, (writer, state) => { var tempBuffer = stackalloc byte[connectionState.ClientRandom.Length * 2 + messageLength]; var tmpSpan = new Span <byte>(tempBuffer, connectionState.ClientRandom.Length * 2 + messageLength); connectionState.ClientRandom.CopyTo(tmpSpan); tmpSpan = tmpSpan.Slice(connectionState.ClientRandom.Length); connectionState.ServerRandom.CopyTo(tmpSpan); tmpSpan = tmpSpan.Slice(connectionState.ServerRandom.Length); bookMark.Span.Slice(0, messageLength).CopyTo(tmpSpan); connectionState.Certificate.SignHash(connectionState.CryptoProvider.HashProvider, connectionState.SignatureScheme, ref writer, tempBuffer, connectionState.ClientRandom.Length * 2 + messageLength); return(writer); }, connectionState); return(buffer); }
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(); } } }
// 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); } } }
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); } }
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); } } }
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); }
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); }
public static void WriteCertificateEntry(ref WritableBuffer writer, byte[] certificate) { writer.Ensure(3); writer.Memory.Write24BitNumber(certificate.Length); writer.Advance(3); writer.Write(certificate); }
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; }
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); } }
public static unsafe void WriteAsciiString(ref WritableBuffer buffer, string value) { // One byte per char buffer.Ensure(value.Length); fixed(char *s = value) { int written = ASCIIEncoding.GetBytes(s, value.Length, (byte *)buffer.Memory.UnsafePointer, value.Length); buffer.CommitBytes(written); } }
public static unsafe void WriteUtf8String(ref WritableBuffer buffer, string value) { fixed(char *s = value) { var byteCount = Utf8Encoding.GetByteCount(value); buffer.Ensure(byteCount); int written = Utf8Encoding.GetBytes(s, value.Length, (byte *)buffer.Memory.BufferPtr, byteCount); buffer.CommitBytes(written); } }
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); }
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); }
public static unsafe void WriteAsciiString(ref WritableBuffer buffer, string value) { // One byte per char buffer.Ensure(value.Length); fixed(char *s = value) { int written = Encoding.ASCII.GetBytes(s, value.Length, (byte *)buffer.Memory.BufferPtr, value.Length); buffer.UpdateWritten(written); } }
/// <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); } }
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}"); } }
public static void WriteRecord(ref WritableBuffer buffer, RecordType recordType, ReadableBuffer plainText, State.IConnectionState state) { buffer.Ensure(RecordHeaderLength); if (state.WriteKey == null) { buffer.WriteBigEndian(recordType); buffer.WriteBigEndian(TlsRecordVersion); buffer.WriteBigEndian((ushort)plainText.Length); buffer.Append(plainText); return; } buffer.WriteBigEndian(RecordType.Application); buffer.WriteBigEndian(TlsRecordVersion); var totalSize = plainText.Length + state.WriteKey.Overhead + sizeof(RecordType); buffer.WriteBigEndian((ushort)totalSize); state.WriteKey.Encrypt(ref buffer, plainText, recordType); }
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(_privateKey.KeySize); var result = _privateKey.SignHash(digest); writer.Write(result); return(result.Length); }
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); } }
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(); }
public void StartFrame(RecordType recordType, ref WritableBuffer buffer) { if (_frameStarted) { ExceptionHelper.ThrowException(new InvalidOperationException("Already writing a frame and started another")); } _frameStarted = true; _recordType = recordType; buffer.Ensure(RecordProcessor.RecordHeaderLength); buffer.WriteBigEndian(recordType); buffer.WriteBigEndian(_state.TlsRecordVersion); _bookmark = buffer.Memory; buffer.WriteBigEndian <ushort>(0); _messageBodySize = buffer.BytesWritten; if (_state.WriteKey == null) { return; } _state.WriteKey.WriteNonce(ref buffer); _plainTextSize = buffer.BytesWritten; }
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); }
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); } }
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(); } } }
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); }
internal static unsafe SecurityStatus Decrypt <T>(this T context, ReadableBuffer buffer, WritableBuffer decryptedData) where T : ISecureContext { void *pointer; if (buffer.IsSingleSpan) { buffer.First.TryGetPointer(out pointer); } else { if (buffer.Length > SecurityContext.MaxStackAllocSize) { throw new OverflowException($"We need to create a buffer on the stack of size {buffer.Length} but the max is {SecurityContext.MaxStackAllocSize}"); } byte * tmpBuffer = stackalloc byte[buffer.Length]; Span <byte> span = new Span <byte>(tmpBuffer, buffer.Length); buffer.CopyTo(span); pointer = tmpBuffer; } int offset = 0; int count = buffer.Length; var secStatus = DecryptMessage(pointer, ref offset, ref count, context.ContextHandle); if (buffer.IsSingleSpan) { buffer = buffer.Slice(offset, count); decryptedData.Append(ref buffer); } else { decryptedData.Ensure(buffer.Length); decryptedData.Write(new Span <byte>(pointer, buffer.Length)); } return(secStatus); }