Comments (34)
I use some encryption with my software to encrypt license keys. I am working on using the same encryption methods to encrypt every message. If I manage to make it work stable, I'll create a PR.
from h.pipes.
Please wait a little. I have already included your code in the main branch, I will change it a little and you will just provide a new PR on top of the master branch.
from h.pipes.
I have changed the way for key exchange. Now the client and the server create a separate byte[] channel for this using the SingleConnection server and client.
from h.pipes.
I am going to sleep. It will be great if you test this and provide feedback. Thank you again for the your work and the provided PRs
from h.pipes.
I'll test it this evening.
from h.pipes.
There's a Heisenbug. It happens when not debugging but when you search for it, it does not occur.
Currently there are two errors I could see but could not diagnose. First one is about serialization / deserialization. There's a byte array sent to a JSON converter, that I could not spot. The second is premature cancelation of a task.
from h.pipes.
I have merged your code and will adapt it a little according to my vision of the project. I need a little explanation about KeyPair.ValidatePublicKey
:
The current implementation does not refer to class fields and can be a static method. Or you have an error, because the out variable and the publicKey field have the same name, and it is the out variable that is visible inside the method.
from h.pipes.
Thank you for the review. I will update my repo and work on that part.
from h.pipes.
I rewrote your code a bit, simplifying the end-use to:
await using var server = new PipeServer<MyMessage>(pipeName, formatter: new InfernoFormatter(new SystemTextJsonFormatter()));
server.EnableEncryption();
await using var client = new PipeClient<MyMessage>(pipeName, formatter: new InfernoFormatter(new SystemTextJsonFormatter()));
client.EnableEncryption();
Please also study the code https://github.com/HavenDV/H.Pipes/tree/master/src/libs/H.Formatters.Inferno for errors in encryption.
from h.pipes.
There is still a potential problem here:
If the client sends messages immediately after ConnectAsync, then the message may arrive unencrypted.
So far, I see a solution to this problem in changing the InfernoFormatter to IAsyncFormatter and waiting for the key via while (Key == null) await Task.Delay;
from h.pipes.
There is also a problem when the server has more than 1 connection, since the Formatter is common for all connections.
from h.pipes.
My take was if the sent message is not a public key, ignore it. If it's a public key, then use it to calculate shared key. Afterwards, go on encrypted. But it's better to handle it in the library, you are right.
In the Validation, I'll add a try catch and keep the length as a check step. I plan to ensure the sent message is a valid public key by using either dotnet core Cryptography library or Inferno. Since try-catch is costly, the precheck of length is still a valid step.
And I think, client can send its public key only after it gets the server public key, or vice versa.
from h.pipes.
There is also a problem when the server has more than 1 connection, since the Formatter is common for all connections.
You are absolutely right. An instance of format is needed for each connection. I only created one KeyPair for each, but a Formatter is also needed for each. A dictionary might not suffice, I believe, there might be another class with Client Id, KeyPair and Formatter. There may be more ways to improve the quality.
from h.pipes.
I have simplified the end-use to:
await using var server = new PipeServer<MyMessage>(pipeName, formatter: new SystemTextJsonFormatter());
server.EnableEncryption();
await using var client = new PipeClient<MyMessage>(pipeName, formatter: new SystemTextJsonFormatter());
client.EnableEncryption();
solving the problem with multiple connections at the same time - I just create an InfernoFormatter for each connection after I get the key.
from h.pipes.
I added PipeConnectionExtensions.WaitExchangeAsync
. It applies to any connection and will wait for the InfernoFormatter to be active.
from h.pipes.
The current challenge is to recreate the problems in the tests so that they can be fixed.
from h.pipes.
The first one is probably this:
Or this:
It sends a byte array but uses Formatter. Byte array cannot be (de)serialized as json. The exception was something like "0x17 is not a valid JSON".
And the cancelation is caused by the same thing because here it has 10 seconds to communicate but could not succeed for reasons.
Since the other one did not succeed for non-alphanumeric characters in byte array that could not be (de)serialized, this line will wait and probably cause the timeout.
from h.pipes.
The timeout is needed to know about problems, instead of the method just waiting forever.
from h.pipes.
I am using serialization byte[]
to json in tests. This works correctly for Newtonsoft.Json/System.Json.
from h.pipes.
I can use BinaryFormatter, but wouldn't that be another problem?
from h.pipes.
WaitExchangeAsync
will wait forever unless you pass a CancellationToken
. I can add an extra timeout there if needed.
from h.pipes.
I am using serialization
byte[]
to json in tests. This works correctly for Newtonsoft.Json/System.Json.
It's probably the byte[]
here has unreadable characters. I used a simple LINQ call chain that casts each byte as char
and concatenate as a string. But Inferno has its own method for this, converting it to a Base16, Base32 or Base64 string. Probably, that's for the best and allow a safe JSON conversion.
from h.pipes.
WaitExchangeAsync
will wait forever unless you pass aCancellationToken
. I can add an extra timeout there if needed.
Since the attempt to send a public key fails, it will always hit the timeout. So yes, having a timeout here is the correct thing. Without it, it would be hard to understand the problem and also it would hang forever.
from h.pipes.
I have another question. Think of TCP handshake. Would it be better to have this key share like that?
- Client sends the public key, waits until it gets a public key. Ignores any other message. Client shuts down if no response is received.
- When server receives a public key, it sends its newly created public key for that pipe. If no valid public key received in a timely manner, disposes the pipe.
- When both successfully shared, then they start communicating.
from h.pipes.
It's probably the
byte[]
here has unreadable characters. I used a simple LINQ call chain that casts each byte aschar
and concatenate as a string. But Inferno has its own method for this, converting it to a Base16, Base32 or Base64 string. Probably, that's for the best and allow a safe JSON conversion.
Can you grab the data that is throwing the exception?
I suspect that this is still a problem with the Formatter you are using - MessagePack
from h.pipes.
byte[] serialization should not depend on content in any way
from h.pipes.
I have another question. Think of TCP handshake. Would it be better to have this key share like that?
- Client sends the public key, waits until it gets a public key. Ignores any other message. Client shuts down if no response is received.
- When server receives a public key, it sends its newly created public key for that pipe. If no valid public key received in a timely manner, disposes the pipe.
- When both successfully shared, then they start communicating.
Yes, I think we need to add Disconnect if an error occurs or timed out while retrieving the key. Both client-side and non-server-side.
from h.pipes.
It's probably the
byte[]
here has unreadable characters. I used a simple LINQ call chain that casts each byte aschar
and concatenate as a string. But Inferno has its own method for this, converting it to a Base16, Base32 or Base64 string. Probably, that's for the best and allow a safe JSON conversion.Can you grab the data that is throwing the exception? I suspect that this is still a problem with the Formatter you are using - MessagePack
Well, I only used the sample project you created. I did not want to make it more complicated.
from h.pipes.
I cannot repeat the behavior you are talking about. Perhaps you have sent special characters or are you using not the most recent code from the master branch?
from h.pipes.
Last night, I rebased my repo with the - then- latest state of the repo. It happened twice. But when I tried to debug it, Iit did not reoccur. I'll rebase with the latest version and try again. But for now, it seems it's OK. If I manage to find it, I'll create a new issue with steps to reproduce. If it cannot be reproduced, then I'll assume it does not exist 👍
from h.pipes.
Hi,
I managed to find it. Here are the steps to reproduce:
- Start an instance and type
server
. - Start an instance and type
client
. - Start another instance and type
client
. - Voila! Get an exception:
Exception: System.Text.Json.JsonException: '...' is an invalid start of a value.
Enter mode('server' or 'client'):
client
Running in CLIENT mode. PipeName: named_pipe_test_server
Enter 'q' to exit
Client connecting...
Connected to server
Exception: System.Text.Json.JsonException: '0xEF' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
---> System.Text.Json.JsonReaderException: '0xEF' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at H.Formatters.SystemTextJsonFormatter.DeserializeInternal[T](Byte[] bytes) in D:\Repos\H.Pipes\src\libs\H.Formatters.System.Text.Json\SystemTextJsonFormatter.cs:line 27
at H.Formatters.FormatterBase.Deserialize[T](Byte[] bytes) in D:\Repos\H.Pipes\src\libs\H.Formatters\FormatterBase.cs:line 39
at H.Pipes.PipeConnection`1.<Start>b__37_0(CancellationToken cancellationToken) in D:\Repos\H.Pipes\src\libs\H.Pipes\PipeConnection.cs:line 124
from h.pipes.
I believe some unit tests are needed for this library but I cannot decide what is a unit.
from h.pipes.
from h.pipes.
In addition, as I understand it, the exception occurs after the keys are received and the encrypted connection is established.
from h.pipes.
Related Issues (20)
- SemaphoreFullException when CancellationToken is cancelled before semaphore is entered
- Feature request: Have a connection identifier on the server based on a client connection HOT 3
- Application getting terminated HOT 5
- The server stops working HOT 8
- Feature request: Support CreatePipeStreamFunc on the client as well
- Handles are not disposed HOT 1
- Implementation questions HOT 1
- Different Send and Receive Types Info Request HOT 1
- Compiler Errors: Tests, 4.8
- .NET 8 support HOT 2
- Does this library support read-only or write-only? HOT 11
- ConsoleApp sample server generates an exception with .NET 8.0 HOT 3
- Couldn't send data in specflow testing application via pipes
- Cannot access a disposed object. HOT 3
- I am getting below issue when i am communicating from .net framework app to .net 7 HOT 6
- MessagePack Unions not serialized correctly. HOT 2
- Security question(s) regarding BinaryFormatter HOT 6
- Explore possibility to use DataFlow Task Parallel library
- Exception in IPC call HOT 3
- MemoryPack support HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from h.pipes.