robertmuth / PyZwaver

Z-Wave library written in Python3
GNU General Public License v3.0
38 stars 8 forks source link

implement security protocols #2

Open robertmuth opened 6 years ago

KM4YRI commented 6 years ago

+1, as even open-zwave hasn't yet implemented S2 security. The OZW developers don't really seem to care either, they just closed an open ticket asking for it, saying why bother when there aren't any S2 devices out there (obviously there are now but still they don't care).

I started looking into what it would take to add S2 security to OZW in a fork, but my C++ skills probably aren't up to the task. I could probably get it done in Python and would volunteer to do that in PyZwaver, if the author doesn't have time to do it. The offer is open though. Not sure what that timetable would be but hopefully the author of this project is more open to it than the authors of openzwave.

robertmuth commented 6 years ago

My plan is to add S2 support but no support for S0. Implementing security will cause quite a bit of churn in the internals of the library.

I have an S2 capable device to play with and hope to get the initial key exchange done this weekend. Since there is no reference implementation, this will be kind of hard and every help is appreciated. I'll post updates and requests for help to this issue.

KM4YRI commented 6 years ago

I'd be happy to assist in testing if needed. I'm just starting out with Z-wave, at the moment I'm actually doing some web scraping of the z-wave alliance site of all the devices to get a more accurate idea of the differences between various devices based on supported classes and their supported versions of them. I'm pretty disappointed that openzwave doesn't support S2 so I'm willing to invest some time to get an implementation going, even if it's just on the support side, helping out where needed. From what I understand, the USB z-wave devices are pretty much just a pipe and all the encryption and security protocols must be handled by the top-level application. I'm assuming that as long as they've got a specification for it that it's enough to make a Python implementation from scratch.

Good luck and feel free to reach out if there's anything I can help with.

robertmuth commented 6 years ago

Implementation work has begun.

This feature will drag in a fairly heavy dependency on "cryptography" (https://cryptography.io/en/latest/)

By default the corresponding import is still disabled. Set SECURE_MODE to True in node.py to enable it.

Development/debugging is currently done using a real device an iterating via

./example_tool.py --verbosity=20 --serial_port=/dev/ttyUSB0 unpair ./example_tool.py --verbosity=30 --serial_port=/dev/ttyUSB0 secure_pair

robertmuth commented 6 years ago

Some progress towards the handling the initial key exchange. A bunch of security primitives related to Security2 are now in security.py

Biggest omissions are around Nonce generation for SPAN. (cf.: http://zwavepublic.com/sites/default/files/command_class_specs_2017A/SDS13783-5%20Z-Wave%20Transport-Encapsulation%20Command%20Class%20Specification.pdf )

The other missing part is unit tests confirming that these primitives actually work as intended. Without those unit tests it will be a long chain of trial and error before the first MessageEncapsulation can be decrypted.

Any help is greatly appreciated

robertmuth commented 6 years ago

Most of the crypto primitives are now in place but have not been fully debugged. The next milestone is to get the unit-test "TestKex" pass. (make test_security) If anybody has spare cycles feel free to send me a pull request.

KM4YRI commented 6 years ago

Question for you, apologies if it's slightly off-topic for this issue.

This USB stick advertizes full S2 security: https://www.thesmartesthouse.com/products/zooz-usb-z-wave-plus-s2-stick-zst10

However my understanding of all common Z-Wave USB sticks was that the serial protocol left all of the S2 security to the end-user application to implement (hence this issue being open). But this product says that S2 is implemented out of the box, and is otherwise transparent.

How can that be? And would it be compatible with PyZwaver and/or OpenZwave?

robertmuth commented 6 years ago

My understanding is that s2 is largely done in software at the application layer. In fact, part of the development I did so far was done with an ancient series 300 usb stick from aeotec. There probably are some advanced features that require a zwave plus (series 500) device but I have not reached that point.

BTW: I wont have much time to work on this till the of the quarter so feel free to give it a try.

aromanro commented 5 years ago

Did you manage to decrypt the first S2 encrypted packet (the 'echo')? I'm implementing the same thing for some closed source project and I'm having troubles with it... ECDH, PRNG and decryption are good as far as I can tell, but there is some mistake in there... it would be nice if they would provide some test vectors for nonce generation, for example...

robertmuth commented 5 years ago

sorry, no progress here. I think the best thing would be to reach out to the z-wave alliances and ask for an example communication transcripts including all the internal state on both sides.

aromanro commented 5 years ago

In the meantime, I managed to decrypt it. It's quite cumbersome to implement it, one needs to patiently check each referred RFC for test vectors and check against those. Apparently it's doable, but it takes patience and time.

aromanro commented 5 years ago

By the way, I've seen this: "My plan is to add S2 support but no support for S0." FYI, S0 is much simpler than S2 to implement, plus you have open source projects that already implement it, so if you get stuck you can look into those to see what they do. There is no open source implementation of S2 as far as I can tell and it's much harder to implement. Besides the S2 class one has to implement for example the transport class which is quite a bit of work by itself.

robertmuth commented 5 years ago

@aromanro if you can post a transcript of the message exchanged of the initial key exchange including the internal crypto state of both sides - that would be tremendously helpful.

Re S0 support, I actually got that to work in a predecessor of this library but I do not think it is worth it. There are too many message that need to be exchanged leading to poor latency/reliability.

aromanro commented 5 years ago

S0 is working nicely in the software I implemented. Indeed there is the overhead of requesting the nonce and getting it each time, but it's not that bad. The reliability does not seem worse than without S0, if implemented right. You can even send an encrypted packet specifying with it that you need another nonce for the next packet, which cuts from overhead a little.

As for that log, I'm not sure I should provide it, since I'm working on a closed source project. My advice would be to check each step from the documentation with patience, and test against the test vectors provided in referred RFCs. That's how I figured it out.

robertmuth commented 5 years ago

Can you point me at the rfc with the test vectors.

aromanro commented 5 years ago

There are various RFCs, pointed out in the documentation. The starting point for S2 implementation is 'Z-Wave-Transport-Encapsulation-Command-Class-Specification' pdf. For DiffieHellman I did what is said in this page http://cr.yp.to/ecdh.html and used gcrypt. For CBC-MAC I used this https://tools.ietf.org/html/rfc3610 for the test vectors at the end and the description which appears to me not so clear, I had a little bit of fighting with it until I managed to decrypt and authenticate. For AES CMAC I used gcrypt, I implemented my own PRNG according to the specs from here: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf Basically I combined using gcrypt, my code and some black magic :) in order to have it working. It's quite a bit of work involved...

robertmuth commented 5 years ago

So I got reasonably far with this in this test: https://github.com/robertmuth/PyZwaver/blob/master/Tests/security_test.py

using a standard python crypt library. I am going to clean it up a little over xmas. Would you be willing to have a look at it and let me know where there first deviation happens compared to your implementation and what the expect value at that point would be?

aromanro commented 5 years ago

Not really, I'm very sick of my own code about this :(

Checking my own code to find where the problems were was nightmare enough, trying to figure that out in some other code is more than I can stand right now, sorry.