zeromq / netmq

A 100% native C# implementation of ZeroMQ for .NET
Other
2.95k stars 744 forks source link

Bad keys #908

Closed slateAGF closed 4 years ago

slateAGF commented 4 years ago

We have used LibZMQ and NetMQ for several years and now wanted to add Curve encryption.

We initially created new key pairs using NetMQ for each test run. But now and again we would get errors and it seems to be the key pair. We are now running with a “known good keypair” with no problems.

Attached is a failing keypair

Environment

NetMQ 4.0.1.2-pre LibZMQ 4.3.2

Operating System: 7, 2010, 2019
.NET Version:     4.8

bad key files.zip

somdoron commented 4 years ago

How did you generate the keys?

slateAGF commented 4 years ago

In our test environment, we had our intergrationtest service generate (NetMQCertificate()) the key and store the files for the various services to load them. It seemed logical since we wipe the directories between builds. Our final attempt:

                var netMqCertificate = new NetMQCertificate();
                File.WriteAllBytes(@"d:\PPGPublic.key", netMqCertificate.PublicKey);
                File.WriteAllBytes(@"d:\PPGSecret.key", netMqCertificate.SecretKey);

                testCase.IntegrationTest.ParkSimArgs += string.Format(" /PPGEncryptionKey=\"{0}---:---{1}\"",
                    Convert.ToBase64String(netMqCertificate.SecretKey),
                    Convert.ToBase64String(netMqCertificate.PublicKey));

Now we have a hardcoded stringpair in the intergrationtest service; it still writes the files and set the parameter. We have not seen issues since the change //Since new NetMQCertificate() does not always generate a valid key, a hardcoded key has been provided var secretkey = Convert.FromBase64String("SYaTZwPp9Mq+1WP+ZsdskWPcukMgECnrToDhA6RTjZM="); var publickey = Convert.FromBase64String("YeOHJ2hXSLfOfpZOtsBEt0Pi3GSF6upVJWaG8Zc5RU8="); var netMqCertificate = new NetMQCertificate(secretkey, publickey); File.WriteAllBytes(@"d:\PPGPublic.key", netMqCertificate.PublicKey); File.WriteAllBytes(@"d:\PPGSecret.key", netMqCertificate.SecretKey);

                testCase.IntegrationTest.ParkSimArgs += string.Format(" /PPGEncryptionKey=\"{0}---:---{1}\"",
                    Convert.ToBase64String(netMqCertificate.SecretKey),
                    Convert.ToBase64String(netMqCertificate.PublicKey));
slateAGF commented 4 years ago

Attached a simple client + server to recreate the problem.

Start the server it creates a new key pair; then start client. The client writes out the keys.

Then stop both and repeat; it should fail in less than 10 attempts.

curve.zip

somdoron commented 4 years ago

Can you make a test at https://github.com/somdoron/NaCl.net that try to reproduce?

somdoron commented 4 years ago

By the way, Curve25519 is 251 bits, so It should fail about 2% of the time. But I don't think this is the case here...

slateAGF commented 4 years ago

Can you make a test at https://github.com/somdoron/NaCl.net that try to reproduce?

Sorry; what are you thinking about in particular?

About 2% failrate; yes we have seen higher rates than that.... we are also considering cooking up a check to validating keypairs.

dxdjgl commented 4 years ago

Having looked into this issue, it seem like it might not be related to the keys. When having a set of server keys which makes libzmq connection fail consistently, I have tried to connect another client using netmq. This connection succeeds, so I suppose the problem is between NetMq and libzmq? It fails in PushMsgResult CurveServerMechanism::ProcessHello(ref Msg msg) where it is unable to decrypt the message. I have even tried to have all keys generated in NetMQ, NetMQ-> LibZmq fail while NetMQ -> NetMQ is okay.

dxdjgl commented 4 years ago

After further investigation, it seems like the problem seems to follow the curve client? The following behaviour has been seen using the "bad" keys. curve client -> curve server netmq -> netmq = ok libzmq -> netmq = not ok libzmq -> libzmq = not ok netmq -> libzmq = ok

dxdjgl commented 4 years ago

The problem is not the key it is reading it from the key file. Use the following code to read the key file and it will work. char readFileBytes(const char name) { std::ifstream fl(name, std::ios::binary); fl.seekg(0, std::ios::end); size_t len = fl.tellg(); auto ret = new char[len]; fl.seekg(0, std::ios::beg); fl.read(ret, len); fl.close(); return ret; }

slateAGF commented 4 years ago

Case closed