bluerange-io / bluerange-mesh

BlueRange Mesh (formerly FruityMesh) - The first completely connection-based open source mesh on top of Bluetooth Low Energy (4.1/5.0 or higher)
https://bluerange.io/
Other
287 stars 109 forks source link

Some questions on working with fruitymesh #139

Closed NilsMinor closed 4 years ago

NilsMinor commented 4 years ago

Hi,

I have a couples of questions in order to develop an application with fruity mesh and I think I will not the only one asking those (hopefully)

1) When creating message structs for mesh communication the structs must be packed. You do something like :

static constexpr int SIZEOF_GPIO_PIN_CONFIG = 2;
    struct gpioPinConfig{
        u8 pinNumber : 5;
        u8 direction : 1; //configure pin as either input (0) or output (1) 
        u8 inputBufferConnected : 1; //disconnect input buffer when port not used to save energy
        u8 pull : 2; //pull down (1) or up (2) or disable pull (0) on pin (GpioPullMode)
        u8 driveStrength : 3; // GPIO_PIN_CNF_DRIVE_*
        u8 sense : 2; // if configured as input sense either high or low level
        u8 set : 1; // set pin or unset it
    };
STATIC_ASSERT_SIZE(gpioPinConfig, 2); 

How to determine the static assert size of 2 in this case and why is it important to do so? I thought it is maybe a multiple of u32 but I found no informations on it.

2) For mesh communication I would like to create an ionic app for my iPhone. I need to scan for devices, send messages to the mesh and receive messages from the mesh. I would like to use some message types already available (scan, enroll ...) as well as my own message types. Do you have any kind of resource on creating an app or do you even provide ionic examples? I found an old BlueRange android sdk but it is from 2017 any piece of informations would be helpful :)

3) Are new features planed or upcoming releases? Is there a roadmap available for fruitymesh?

Thanks a lot and best regards, Nils

mariusheil commented 4 years ago

Hi,

1) When pragma pack(1) is used, you will have non-padded (padded to full bytes) structs with 1 byte alignment. So the above gives you 2 bytes because all the bits summed up use 15 bits. However, the above looks like you are not using it for mesh communication, so you do not need to pack it if it is not necessary. This is only important if stuff is passed over the network so that it defines a compatible protocol and does not change between different versions.

2) We do have some internal applications, but not an open source sdk at the moment. I think this is important and I will mention it to our product team. The old example is probably not useful for you. The documentation about MeshAccessConnections, together with the code should allow you to build something for iOS or Android as I know of a few people who successfully did this. I will report back if I have anything new.

3) I think we just released a new version, but we do not have a fixed roadmap as we are often working on customer projects and implementing stuff as we need it, Is there anything specific you are missing? Then maybe I can give you an estimate.

Brotcrunsher commented 4 years ago

In addition to what Marius already said:

  1. The posted piece of code comes from the IoModule which can send out these structs via BLE (see pinset command). That's the reason why the STATIC_ASSERT_SIZE is placed there, just to make sure that no compiler that we might ever use does something funny there and adds e.g. some unwanted padding (because pack(1) is none standard and its exact behavior differs between compilers). How we determined that it should be the specific size 2 in this case is rather simple: because it is on GCC (and as it still compiles with MSVC and Clang, its the case for them as well).
NilsMinor commented 4 years ago

Hi @mariusheil and @Brotcrunsher thanks! 1) Yes the piece of code is from the IoModule and is a fruitymesh message. The padding to full bytes was something I did not know but makes sense to me. So I will do this for all my message types as well. When testing, I set the example message struct size (2 bytes in real) to 10 and I worked, but I think it might be better to set it to the real , calculated size :D

2) Thanks, yeah this would be very important to most applications. I think this is the biggest benefit from the fruitymesh approach compared to other wireless mesh protocol, It runs an able and users so could connect directly to the mesh with their phone. I will definitely give it a try!

3) Yes you released a new version, It was just a question for my personal interest. I think there is nothing specific right know but like always - new releases will always give new ideas on where to use fruitymesh :)

Thanks for your support! Nils

NilsMinor commented 4 years ago

Hi @mariusheil,

I think I need some advices from you :). I started on working on the App for my application, as explained I am using Inonic (also started to learn Inonic :D). However, my app runs on an iPhone, I was able to scan for devices and found my fruitymesh node. When trying to connect to the device I get a short connection, maybe 1 second. I also see the blinking led on my device stops and behaves like normal connection between two fruitymesh nodes.

The repsonse from the connection call looks like:

Bildschirmfoto 2020-07-02 um 22 13 46

Sorry for the image instead of code, I was not able to copy the object out from safari web inspector.

Can you give me some advices on what's next? My goal is to communicate with my fruitymesh node vie smartphone. Why is my app not connecting ? How to communicate to the mesh?

Many thanks for any hint! Best regards Nils

mariusheil commented 4 years ago

Hello,

the FruityMesh nodes will automatically disconnect after a short time if the partner makes no attempts to set up a securely encrypted connection. This protects them from using up all their connections. If you want to disable this for testing, you should look in the logs of the node and find the log statement where the disconnection is made and comment out that part. If you have the services discovered, there should be a characteristic that you can use for writing: `constexpr u8 MA_SERVICE_BASE_UUID[] = { 0x58, 0x18, 0x05, 0xA0, 0x07, 0x0C, 0xFD, 0x93, 0x3C, 0x42, 0xCE, 0xAC, 0x00, 0x00, 0x00, 0x00 };

constexpr int MA_SERVICE_SERVICE_CHARACTERISTIC_UUID = 0x0001; constexpr int MA_SERVICE_RX_CHARACTERISTIC_UUID = 0x0002; constexpr int MA_SERVICE_TX_CHARACTERISTIC_UUID = 0x0003; constexpr int MA_CHARACTERISTIC_MAX_LENGTH = 20;`

You will have to write the first packet of the encryption handshake in this characteristic.

We have a flutter plugin in its early stages with native Android and native iOS code. We are planning on open sourcing that, but I do not have a timeline yet. I will ask around and I might be able to give you some code snippets, but not sure yet.

Basically everything you need to implement is also implemented in the MeshAccessModule. You can use the "action ma connect" command to connect to a node in a different network by giving the keyType and the key. If you enable most of the MACONN and MAMOD debug messages, you will see all the packets that are being transmitted for the handshake and how the encrypted connection can then be used to send packets.

NilsMinor commented 4 years ago

Hi @mariusheil,

thanks a lot to clarify the right way creating a mesh connection via app. I will try the way you mentioned and will start with removing the disconnection function. But my goal is of course to follow the fruitymesh process and try to connect with encryption but in the second step.

I found the services you mentioned. I read the mesh access documentation that is very helpful for my purpose (sorry for not doing this first!).

I hope I can achieve what I am planing to do using ironic, I do not know if the API give me enough access and functionality for connecting to the mesh and my nodes and read/write to the nodes.

I think already code snippets will help me a lot, this would be awesome ! :)

I will let you know If it is working for me. Thanks a lot for supporting fruitymesh!

Best regards, Nils

mariusheil commented 4 years ago

Are you trying to use ionic with some kind of BLE plugin directly? We are using a native (Java) plugin, and Objective-C for iOs to do that. It is also possible to use a generic BLE plugin for ionic and do all of that stuff in Javascript. One of our customers did that. I will ask what plugin they were using.

mariusheil commented 4 years ago

Hi,

I got a response and this seems to be the plugin they are using, so that should work https://github.com/randdusing/cordova-plugin-bluetoothle

If you get sth. working it would be great if you could open source that :-)

NilsMinor commented 4 years ago

Hi,

yes I want to use ionic with a ble plugin. Thanks for sharing the plugin a customer of you used :) I started using the cordova-plugin-ble-central plugin but I will give your bluetoothle plugin a try. For implementing the connection scheme it would still be very useful to share some snippets either from Objective-C or java just to understand the sequence, if this is possible to you:)

And of course, all my private project are open source so I will of course share the code :D

NilsMinor commented 4 years ago

Hi @mariusheil ,

I am making progress but I really need some support in order to create a valid fruity-mesh ionic plugin.

I was able to scan for the device and could connect but as described, it disconnects because of no handshake. I removed the disconnect event from the fruity-mesh code but this seams wrong to me in order to make a valid plugin.

The docs https://www.bluerange.io/docs/fruitymesh/MeshAccessModule.html describes the handshake process. When I connect, I start the Notification on tx characteristic. Now I need to implement the handshaking process but I have no glue how to do this. I have added my current code below. I was not able to found more about handshaking and sending the nonce/snonce/anonce using Ionic so, some code snippets would by really really awesome ^^

private onHandleCharacteristics(device: FruityMeshDevice): void {
        if (device && device.characteristics.length > 0) {

            const rxService = device.characteristics.find(c => c.characteristic === FruityMeshGATTServiceDefinition.RX_HANDLE);
            const txService = device.characteristics.find(c => c.characteristic === FruityMeshGATTServiceDefinition.TX_HANDLE);

            if (txService) {
                console.log('rxService ', txService);
                this.ble.startNotification(device.id, txService.service, txService.characteristic).subscribe(data => {
                        console.log('notify :', data);
                    }, error => {
                        console.log('error :', error);
                    }
                );
                const value = new Uint8Array([1234]);
                this.ble.write(device.id, rxService.service, rxService.characteristic, value).then(
                    data => console.log('read :', data)
                );
            }
        }
    }

Thanks for your support, Nils

NilsMinor commented 4 years ago

Hi @mariusheil ,

I made some further investigations but I am still not able to create a connection. After scanning I try to connect. The response is the list of services and characteristic. I try to start the handshake process by writing th the rx service.

I run the following code that I derived from your docs to build the msg to write to the rx service.

const messageType = arr8bit(FruityMeshEncryptionMessageType.START);
const senderId = arr16bit(NODE_ID_APP_BASE);
const receiverId = arr16bit(0);
const version = arr8bit(1);
const keyId = arr32bit(1234);
const tunnelType = arr8bit(TUNNEL_TYPE_REMOTE_MESH << 2); 

This generates this bit array in little endian : 25,0,125,0,0,1,210,4,0,0,4

The serial output from my device prints this :

GAPController.cpp@125 C]: Connected device
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:E7:0E:34:00:00:00:00, len 23
[ResolverConnection.cpp@47 RCONN]: New Resolver Connection
[BaseConnection.cpp@604 CONN]: Incoming connection 0 connected
[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:E7:0E:34:00:00:00:00, len 23
{„type“:“update_joinme“,“clusterId“:4274663043,“clusterSize“:1}
[GAPController.cpp@119 C]: Disconnected device 22
{„type“:“live_report“,“nodeId“:11907,“module“:3,“code“:52,“extra“:0,“extra2“:22}

But I do not get a response from the device in my app. I do not really understand ho to create the keyId and I am not sure if I build the packet. As described any code snippets would help a lot. Is the overall process I am doing is right?

Best regards, Nils

mariusheil commented 4 years ago

Hi,

can you send me an e-mail to marius.heil@mway.io? As we do not currently have the code in a state that we can open source, I can provide you with some stuff privately.

If you are the central, you should start by registering for notifications on the TX characteristic of the service before you write any data. See MeshAccessConnection::RegisterForNotifications(). Then you need to implement the start of the handshake as seen in MeshAccessConnection::StartHandshake(FmKeyId fmKeyId).

In the log of the Node, you should then see a log output "-- TX ANonce, fmKeyId...." if that packet was received correctly.

You can type "status" right after you are connected to see if you only have a ResolverConnection or if you have a MeshAccessConnection. If you only have a resolver connection, that means that you did not send data to the correct characteristic (the content of the packet does not matter at this point). Maybe add a log to the MeshAccessConnection::ConnTypeResolver method to see if this is being called after you send data and if it correctly resolves as a MeshAccessConnection.

Writing to the RX characteristic is correct, but I cannot see anything in the log that indicates that your write actually succeeded. So there must be sth. missing. You should enable the logtags MACONN and CONN_DATA to see everthing that is being received. You could also try to activate all logts "debug all" and see if there is any indication that you are writing data.

Marius

NilsMinor commented 4 years ago

Hi @mariusheil ,

I am making progress :D I figured out how to subscribe to the notification tx characteristic and rebuild the MessageHandshakeStart message from your example. So my process looks like:

Send the handshake start message. My packet looks like :

Uint8Array (11) : 25 125 0 0 0 1 0 0 0 2 1

My fruity mesh device prints this:

[GAPController.cpp@125 C]: Connected device
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23
[ResolverConnection.cpp@47 RCONN]: New Resolver Connection
[BaseConnection.cpp@604 CONN]: Incoming connection 0 connected
[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
[MeshConnection.cpp@83 MACONN]: MeshConnResolver
[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
[MeshConnection.cpp@83 MACONN]: MeshConnResolver
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23
[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection
[BaseConnection.cpp@604 CONN]: Incoming connection 0 connected
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23
[MeshAccessConnection.cpp@265 MACONN]: — TX ANonce, fmKeyId 33554432
[MeshAccessConnection.cpp@512 MACONN]: Using derived user key 33554432
[MeshAccessConnection.cpp@824 MACONN]: MA SendData from 12599 to 14599
[MeshAccessModule.cpp@618 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@123 MACONN]: Deleted MeshAccessConnection, discR: 0, appDiscR: 1
[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23
{„type“:“update_joinme“,“clusterId“:3531223351,“clusterSize“:1}
[GAPController.cpp@119 C]: Disconnected device 22
{„type“:“live_report“,“nodeId“:12599,“module“:3,“code“:52,“extra“:0,“extra2“:22}

I received this packet from the fruity mesh device as response for my MessageHandshakeStart:

Uint8Array (20) : 71 106 99 120 102 81 66 104 118 80 73 112 49 120 77 43 102 81 61 61 As correct answer to my handshake start message I was waiting for a 26 (MESSAGE_TYPE_ENCRYPT_CUSTOM_ANOUNCE) but I got a 71 and I am confused. How should I interpret this message packet? Is this encrypted or to I have to cast it to other data type?

Thanks for your support, Nils

mariusheil commented 4 years ago

Hi,

I will check in more detail tomorrow, but you could try to enable the conn_data logtag to get a log of the sent response packet from the node, then you could compare the printed hex data to the data that you received.

Marius

Nils Minor notifications@github.com schrieb am So., 2. Aug. 2020, 22:46:

Hi @mariusheil https://github.com/mariusheil ,

I am making progress :D I figured out how to subscribe to the notification tx characteristic and rebuild the MessageHandshakeStart message from your example. So my process looks like:

Send the handshake start message. My packet looks like :

Uint8Array (11) : 25 125 0 0 0 1 0 0 0 2 1

My fruity mesh device prints this:

[GAPController.cpp@125 C]: Connected device

[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23

[ResolverConnection.cpp@47 RCONN]: New Resolver Connection

[BaseConnection.cpp@604 CONN]: Incoming connection 0 connected

[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data

[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2

[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data

[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2

[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23

[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection

[BaseConnection.cpp@604 CONN]: Incoming connection 0 connected

[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23

[MeshAccessConnection.cpp@265 MACONN]: — TX ANonce, fmKeyId 33554432

[MeshAccessConnection.cpp@512 MACONN]: Using derived user key 33554432

[MeshAccessConnection.cpp@824 MACONN]: MA SendData from 12599 to 14599

[MeshAccessModule.cpp@618 MACONN]: Message auth is 1

[MeshAccessConnection.cpp@123 MACONN]: Deleted MeshAccessConnection, discR: 0, appDiscR: 1

[MeshAccessModule.cpp@326 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00, len 23

{„type“:“update_joinme“,“clusterId“:3531223351,“clusterSize“:1}

[GAPController.cpp@119 C]: Disconnected device 22

{„type“:“live_report“,“nodeId“:12599,“module“:3,“code“:52,“extra“:0,“extra2“:22}

I received this packet from the fruity mesh device as response for my MessageHandshakeStart:

Uint8Array (20) : 71 106 99 120 102 81 66 104 118 80 73 112 49 120 77 43 102 81 61 61 As correct answer to my handshake start message I was waiting for a 26 (MESSAGE_TYPE_ENCRYPT_CUSTOM_ANOUNCE) but I got a 71 and I am confused. How should I interpret this message packet? Is this encrypted or to I have to cast it to other data type?

Thanks for your support, Nils

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mwaylabs/fruitymesh/issues/139#issuecomment-667722753, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABM62NCL2EKYYRYP44TE7ZLR6XGCXANCNFSM4NVZPRBA .

NilsMinor commented 4 years ago

Hi Marius, thanks for your feedback. I will enable this tag later and I will try to compare the message the device send and the message I receive. However It would be create if you could check my printouts :) BR, Nils

======================UPDATE ============================ Your tip helped me @mariusheil , the data packet that was sent to my service looked good. I had to decode the bluetooth data (bluetoothle.encodedStringToBytes(obj.value)) so no I can start to implement the NONCE handling :D

NilsMinor commented 4 years ago

Hi @mariusheil , i need some more help ^^. I am implementing the encryption manager and I need to know the networkKey. I am not able to receive the broadcast data with my BluetoothLE ionic plugin, or I did not figured it out correctly. I receive can manufacturerData from the advertisement object (TQLwCwABNzE3Mbu6AQAaAAQB//8QAAAAAAA=) but it has an encoded length of 26 and my broadcast message from the device looks like (02:01:06:03:03:12:FE:0F:16:12:FE:03:00:0B:00:09:0C:F1:55:00:00:00:00) and has a length of 23.

So I am not able to get the network key from the broadcast message. I looked in the code, should I use 00 16 as networkKey? Thanks, Nils

mariusheil commented 4 years ago

Hi,

I am not sure that I got it correctly. Where did you get that base64 encoded String from? Was it from your Ionic plugin? Why is it in base64? If it was from fruitymesh, can you paste me a part of the log where I can see this? I do not know, which network key from a broadcast message you are expecting. The network key is of course not broadcasted as it is secret and has to be known by both devices. It is set during enrollment, or probably in your case hardcoded for now.

If you do not have UICR data, which I suppose, the network key is written in the github_nrf52.cpp in this line: CheckedMemset(c->networkKey, 0x00, 16);

So the key is: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00

I am not 100% sure that this works as intended, but I think it should. To be 100% sure, you could replace that line by using 0x11 instead so you have a key 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11

Marius

NilsMinor commented 4 years ago

Yes, the bas64 encoded string is from the scan packet of my ionic bluetooth plugin. The data is set in the manufacturerData field. The raw data looks like : Uint8Array (26) 77 2 240 11 0 1 55 49 55 49 187 186 1 0 26 0 4 1 255 255 16 0 0 0 0 0

Yep you are right of course, I did not understand the networkKey scheme. I will test the 00:00 ... key first. I need this for the encryption manager to set the userKey, is this correct? The userKey is used to generate my sessionEncryptionKey right? ^^

mariusheil commented 4 years ago

Hi,

yes, I always use https://cryptii.com/pipes/base64-to-hex for conversion, so this is the hex data: "4d 02 f0 0b 00 01 37 31 37 31 bb ba 01 00 1a 00 04 01 ff ff 10 00 00 00 00 00"

This starts with 4d 02 which is an little endian u16 and means 0x024D, which is the manufacturer id for our company (M-Way Solutions), the next byte is f0 and corresponds to the MESH_IDENTIFIER of Fruitymesh. What you scanned here is the manufacturer specific message part of the JOIN_ME packet that is used by the nodes to connect to each other, see here: https://www.bluerange.io/docs/fruitymesh/Specification.html#_advertising_packet_with_manufacturer_specific_data

If you type "advjobs" in the terminal, you can see all the different advertising messages that are broadcasted by a fruitymesh node, these are scheduled to rotate each few milliseconds. The MeshAccessBroadcast message should be sent as well, so just scan that device for a little longer and check all the messages coming in. The MeshAccessBroadcast message does however not use a manufacturer specific message! It uses a special 16bit service UUID that we have bought, which is 0xFE12, see https://www.bluerange.io/docs/fruitymesh/MeshAccessModule.html#_meshaccess_broadcast_messages)

You need to query your ionic plugin for the scanned list of Service UUIDs instead of the manufacturer specific data field.

Next, as for the keys: You have different possibilities to connect to a FruityMesh node, using any of these keys: https://www.bluerange.io/docs/fruitymesh/Specification.html#EncryptionKeys You are the one to decide which key should be used, once you act as a Central (e.g. with a Smartphone) and connect to the node. In the initial packet, you give the key id. For your case, the networkKey is fine and allows you to use the same key to connect to all of your nodes in one network with full access right to do everything you like, other keys (e.g. the user keys) are more restrictive. With these, you can program your nodes to only offer limited functionality for other users.

You will use the networkKey to generate the session encryption key, you do not have to care for the other keys at the moment. If you have the logs enabled (MACONN and MAMOD) and you build a mesh access connection between two nodes, you will see all the necessary steps.

I have collected a log for you between two of my development nodes with the serial numbers BBDG3 and BBDF1. I commented in some of the commented out logs in MeshAccessConnection.cpp for logging the generated keys. I also extended the log statements to log out both parts of the nonce (part0 and part1).

First, I enrolled both in different networks but with the same networkkey so that they do not connect to each other using a MeshConnection: Node 1: action this enroll basic BBDG3 1 111 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11 Node 2: action this enroll basic BBDF1 2 222 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11

Then I connected node 1 with node 2 using the command: Node 1: action this ma connect DA:B9:72:4F:A8:60 2 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11 1

I have added some annotations to the log starting with >>>>>.

Log of Node 1

mhTerm: action this ma connect DA:B9:72:4F:A8:60 2 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11 1
[MeshAccessModule.cpp@468 MAMOD]: Received connect task
[MeshAccessModule.cpp@344 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:6F:00:0B:97:07:00:00:00:00:00, len 23
[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection
[GAPController.cpp@112 CONN]: pairing
[MeshAccessConnection.cpp@203 MACONN]: Trying to connect
[GAPController.cpp@125 C]: Connected device
[BaseConnection.cpp@614 CONN]: Outgoing connection 0 connected
[GATTController.cpp@56 GATTCTRL]: Starting Service discovery 0001 type 3, connHnd 0
[FruityHalNrf.cpp@1577 ERROR]: ########################BLE DB EVENT
[GATTController.cpp@68 GATTCTRL]: DB Discovery Event
[MeshAccessConnection.cpp@1111 MACONN]: Service discovered 1
[MeshAccessConnection.cpp@1119 MACONN]: Found service
[MeshAccessConnection.cpp@1124 MACONN]: Found rx char 20
[MeshAccessConnection.cpp@1119 MACONN]: Found service
[MeshAccessConnection.cpp@1131 MACONN]: Found tx char 22 with cccd 23
[MeshAccessConnection.cpp@221 MACONN]: Registering for notifications
[MeshAccessConnection.cpp@239 MACONN]: -- TX Start Handshake
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 1 to 2001
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@329 MACONN]: -- TX SNonce, anonce 3862350040, 4087081004
>>>>> Custom key simply means, that we provided the key manually as 11:11:11:.......11, it is still the networkkey (key type 2)
[MeshAccessConnection.cpp@505 MACONN]: Using custom key
>>>>> This is building the cleartext data for the session encryption key using the ANonce given above (3862350040, 4087081004), you can see the hex value 0xE636C8D8 and 0xF39BE82C in the SessionKeyCleartext prefixed by two bytes NodeId.
[MeshAccessConnection.cpp@550 ERROR]: LongTerm Key is 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11
[MeshAccessConnection.cpp@565 ERROR]: SessionKeyCleartext 01:00:D8:C8:36:E6:2C:E8:9B:F3:00:00:00:00:00:00
[MeshAccessConnection.cpp@505 MACONN]: Using custom key
>>>>> This is the cleartext for the session decryption key generated from the SNonce, again prefixed by two bytes nodeId, snonce should be 0x8787750E and 0x0476F886.
[MeshAccessConnection.cpp@550 ERROR]: LongTerm Key is 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11
[MeshAccessConnection.cpp@565 ERROR]: SessionKeyCleartext 01:00:0E:75:87:87:86:F8:76:04:00:00:00:00:00:00
>>>>> The two cleartexts are now encrypted using the long term key 11:11:11:......:11, which gives you the session encryption keys
[MeshAccessConnection.cpp@609 MACONN]: EncrKey: 7B:10:EE:29:F4:66:11:3B:1B:FD:C6:75:EB:EF:52:31
[MeshAccessConnection.cpp@610 MACONN]: DecrKey: 97:FF:E3:D6:D4:AF:38:CC:80:27:3E:DD:C2:4F:F3:1F
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 1 to 2001
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
>>>>> Now, some data is being sent, first you see the cleartext and the nounce that will be used to encrypt this message. A keystream is generated by using the encryption nonce (see MeshAccessConnection::EncryptPacket). This keystream is then xored with the message and the result is logged out (see "Encrypted as ....")
[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1B:01:00:02:00:0E:75:87:87:86:F8:76:04 (13) with nonce 4087081004
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream 85:39:E9:56:01:F3:DA:15:E6:0C:F5:C2:6C:F6:A0:5E
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 4087081005 produces Keystream 7A:DE:23:6E:FF:9B:E6:A1:41:25:97:52:D8:AF:C6:9F
[MeshAccessConnection.cpp@687 MACONN]: Encrypted as 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68:7A:DE:23:6E (17)
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 1 to 0
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@627 MACONN]: Encrypting 17:01:00:00:00:00:00:00:00:01:00:00:00:01 (14) with nonce 4087081006
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream 5B:21:3E:A2:6C:96:87:BE:A8:5A:B0:2E:C8:1A:93:4B
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 4087081007 produces Keystream 2C:2C:40:5D:D1:40:4F:8F:CB:84:6E:60:3D:32:18:10
[MeshAccessConnection.cpp@687 MACONN]: Encrypted as 4C:20:3E:A2:6C:96:87:BE:A8:5B:B0:2E:C8:1B:2C:2C:40:5D (18)
{"nodeId":1,"type":"ma_conn_state","module":10,"requestHandle":0,"partnerId":2001,"state":4}
[MeshAccessConnection.cpp@388 MACONN]: Handshake done as Central
>>>> The same goes for received messages using the session decryption key instead
[MeshAccessConnection.cpp@695 MACONN]: Decrypting DF:EF:60:25:77:3D:D6:6D:74:45 (10) with nonce 74905734
[MeshAccessConnection.cpp@738 ERROR]: Keystream C3:ED:60:24:77:3D:2E:49:B9:0F:44:2E:11:6A:3C:75
[MeshAccessConnection.cpp@749 ERROR]: MIC nonce 74905736, Keystream C3:ED:60:24:77:3D:2E:49:B9:0F:44:2E:11:6A:3C:75
[MeshAccessConnection.cpp@753 MACONN]: Decrypted as DF:EF:60:25:77:3D (6) micValid 1
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@1055 MACONN]: Received remote mesh data 1C:02:00:01:00:00 (6) from 2001
[MeshAccessConnection.cpp@695 MACONN]: Decrypting 95:BB:FE:B9:2C:9D:33:CC:4A:78:58:AF:EE:24:00:B2:84:3A (18) with nonce 74905736
[MeshAccessConnection.cpp@738 ERROR]: Keystream 82:B9:FE:B9:2C:9D:33:CC:4A:79:58:AF:EE:25:CA:D4
[MeshAccessConnection.cpp@749 ERROR]: MIC nonce 74905738, Keystream 82:B9:FE:B9:2C:9D:33:CC:4A:79:58:AF:EE:25:CA:D4
[MeshAccessConnection.cpp@753 MACONN]: Decrypted as 95:BB:FE:B9:2C:9D:33:CC:4A:78:58:AF:EE:24 (14) micValid 1
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@1055 MACONN]: Received remote mesh data 17:02:00:00:00:00:00:00:00:01:00:00:00:01 (14) from 2001

Log of Node 2:

[GAPController.cpp@125 C]: Connected device
[MeshAccessModule.cpp@344 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:DE:00:0B:77:07:00:00:00:00:00, len 23
[ResolverConnection.cpp@47 RCONN]: New Resolver Connection
[BaseConnection.cpp@612 CONN]: Incoming connection 0 connected
[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
[MeshAccessModule.cpp@344 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:DE:00:0B:77:07:00:00:00:00:00, len 23
[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection
[BaseConnection.cpp@612 CONN]: Incoming connection 0 connected
[MeshAccessModule.cpp@344 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:0F:16:12:FE:03:00:DE:00:0B:77:07:00:00:00:00:00, len 23
[MeshAccessConnection.cpp@269 MACONN]: -- TX ANonce, fmKeyId 2
[MeshAccessConnection.cpp@518 MACONN]: Using network key
[MeshAccessConnection.cpp@550 ERROR]: LongTerm Key is 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11
[MeshAccessConnection.cpp@565 ERROR]: SessionKeyCleartext 01:00:D8:C8:36:E6:2C:E8:9B:F3:00:00:00:00:00:00
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 2 to 2002
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@695 MACONN]: Decrypting 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68:7A:DE:23:6E (17) with nonce 4087081004
[MeshAccessConnection.cpp@738 ERROR]: Keystream 85:39:E9:56:01:F3:DA:15:E6:0C:F5:C2:6C:F6:A0:5E
[MeshAccessConnection.cpp@749 ERROR]: MIC nonce 4087081006, Keystream 85:39:E9:56:01:F3:DA:15:E6:0C:F5:C2:6C:F6:A0:5E
[MeshAccessConnection.cpp@753 MACONN]: Decrypted as 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68 (13) micValid 1
[MeshAccessConnection.cpp@396 MACONN]: -- TX Handshake Done, snonce 0, 0
[MeshAccessConnection.cpp@518 MACONN]: Using network key
[MeshAccessConnection.cpp@550 ERROR]: LongTerm Key is 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11
[MeshAccessConnection.cpp@565 ERROR]: SessionKeyCleartext 01:00:0E:75:87:87:86:F8:76:04:00:00:00:00:00:00
[MeshAccessConnection.cpp@609 MACONN]: EncrKey: 97:FF:E3:D6:D4:AF:38:CC:80:27:3E:DD:C2:4F:F3:1F
[MeshAccessConnection.cpp@610 MACONN]: DecrKey: 7B:10:EE:29:F4:66:11:3B:1B:FD:C6:75:EB:EF:52:31
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 2 to 2002
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1C:02:00:01:00:00 (6) with nonce 74905734
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream C3:ED:60:24:77:3D:2E:49:B9:0F:44:2E:11:6A:3C:75
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 74905735 produces Keystream D6:6D:74:45:04:9E:6A:87:2B:D7:DE:DA:72:71:38:14
[MeshAccessConnection.cpp@687 MACONN]: Encrypted as DF:EF:60:25:77:3D:D6:6D:74:45 (10)
[MeshAccessConnection.cpp@841 MACONN]: MA SendData from 2 to 0
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@627 MACONN]: Encrypting 17:02:00:00:00:00:00:00:00:01:00:00:00:01 (14) with nonce 74905736
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream 82:B9:FE:B9:2C:9D:33:CC:4A:79:58:AF:EE:25:CA:D4
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 74905737 produces Keystream 00:B2:84:3A:BA:7F:F7:B4:5C:3B:29:AD:95:C4:AF:8D
[MeshAccessConnection.cpp@687 MACONN]: Encrypted as 95:BB:FE:B9:2C:9D:33:CC:4A:78:58:AF:EE:24:00:B2:84:3A (18)
[MeshAccessConnection.cpp@443 MACONN]: Handshake done as Peripheral
[MeshAccessConnection.cpp@695 MACONN]: Decrypting 4C:20:3E:A2:6C:96:87:BE:A8:5B:B0:2E:C8:1B:2C:2C:40:5D (18) with nonce 4087081006
[MeshAccessConnection.cpp@738 ERROR]: Keystream 5B:21:3E:A2:6C:96:87:BE:A8:5A:B0:2E:C8:1A:93:4B
[MeshAccessConnection.cpp@749 ERROR]: MIC nonce 4087081008, Keystream 5B:21:3E:A2:6C:96:87:BE:A8:5A:B0:2E:C8:1A:93:4B
[MeshAccessConnection.cpp@753 MACONN]: Decrypted as 4C:20:3E:A2:6C:96:87:BE:A8:5B:B0:2E:C8:1B (14) micValid 1
[MeshAccessModule.cpp@652 MACONN]: Message auth is 1
[MeshAccessConnection.cpp@1063 MACONN]: Received data for local mesh 17:01:00:00:00:00:00:00:00:01:00:00:00:01 (14) from 2002 aka 2002

There are two session keys calculated on both sides that will match. One key for encryption, one key for decryption. One part of the nonce stays the same during the connection (should technically increase after 2^32 packets were sent), the other part of the nonce is increased every time to generate a different keystream for each message.

Marius

mariusheil commented 4 years ago

I added some comments to the log above

NilsMinor commented 4 years ago

Hi @mariusheil you are awesome, thanks a lot for taking your time to create this communication between the nodes ! I will give this a try to implement in my ionic plugin next evenings :D

Thanks a lot never got this good support before ! BR, Nils

NilsMinor commented 4 years ago

Hi Marius, I am struggling to find the correct way to implement the AES encryption. In your example you have : key >> 11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11 clear >> 01:00:0E:75:87:87:86:F8:76:04:00:00:00:00:00:00 and you get this result after encryption >> 97:FF:E3:D6:D4:AF:38:CC:80:27:3E:DD:C2:4F:F3:1F When I do the same AES encryption I get this result link to aes encryption

Am I performing the wrong encryption or am I using the wrong data?

mariusheil commented 4 years ago

Hi, I am currently too dumb to share a link of my edit, but I cannot find the share button. I entered 00000000000000000000000000000000 for the IV and used 01000E75878786F87604000000000000 as the input That gave me the output that you said I was getting 97:FF:E3:D6:D4:AF:38:CC:80:27:3E:DD:C2:4F:F3:1F.

It also gave me 16 more bytes and I am not quite sure why, but the result was correct. Also tested the same thing using cryptii and gave the same result, however I could not find the ECB mode on cryptii and used one of the chaining modes instead.

NilsMinor commented 4 years ago

Thanks ! This helps me to figure out why my AES encryption always gives me different results ^^

NilsMinor commented 4 years ago

Hi Marius,

i have a question to generate the mic . I figured out how to do the AES encryption using ECB with your explanation. :D

I am no trying to encrypt a message using your example :

[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1B:01:00:02:00:0E:75:87:87:86:F8:76:04 (13) with nonce 4087081004
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream 85:39:E9:56:01:F3:DA:15:E6:0C:F5:C2:6C:F6:A0:5E
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 4087081005 produces Keystream 7A:DE:23:6E:FF:9B:E6:A1:41:25:97:52:D8:AF:C6:9F
[MeshAccessConnection.cpp@687 MACONN]: Encrypted as 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68:7A:DE:23:6E (17)

My code is inspired from your android example and looks like :

public encryptMessage(data: Uint8Array): Uint8Array {
        // generate keyStream1
        const copy = data.slice(0);
        const encryptionNounce = new Packet(16);
        encryptionNounce.set32Bit(0, this.encryptionNounce[0]);
        encryptionNounce.set32Bit(4, this.encryptionNounce[1]);
        const keyStream1 = this.encrypt(this.sessionEncryptionKey, encryptionNounce.getData());

        this.encryptionNounce[1] = incrementUint(this.encryptionNounce[1]);

        encryptionNounce.set32Bit(0, this.encryptionNounce[0]);
        encryptionNounce.set32Bit(4, this.encryptionNounce[1]);

        const keyStream2 = this.encrypt(this.sessionEncryptionKey, encryptionNounce.getData());
        this.encryptionNounce[1] = incrementUint(this.encryptionNounce[1]);

        console.log('data', getDataAsString('hex', data));
        console.log('sessionEncryptionKey', getDataAsString('hex', this.sessionEncryptionKey));
        console.log('keystream1', getDataAsString('hex', keyStream1));
        console.log('keystream2', getDataAsString('hex', keyStream2));

        // xor data with keystream

        xorData(keyStream1, data);

        const dataCopy = new Uint8Array(data.buffer.slice(0));

        xorData(keyStream1, dataCopy);

        const mic = new Uint8Array(4);
        mic.set(this.encrypt(this.sessionEncryptionKey, dataCopy).slice(0, 4));

        console.log('mic : ', getDataAsString('hex', mic));

        const encryptedData = new Uint8Array(data.length + mic.length);
        encryptedData.set(data);
        encryptedData.set(mic, data.length);

        console.log('encryptedData ', getDataAsString('hex', encryptedData));

        return encryptedData;
    }

I get the sam keystream1 like you but the keystream2 is different and this results in a different MIC but I can't figure out what is wrong, are you sure with your keystream2?

My output is :

Bildschirmfoto 2020-08-14 um 23 00 11

Thanks, Nils

NilsMinor commented 4 years ago

Hi @mariusheil any thoughts on my MIC calculation? :)

mariusheil commented 4 years ago

Hi,

I would need to test this tomorrow. Good that you wrote again, I missed the initial question. I am pretty sure with the second keystream as this has been implemented by 3 independent parties by now. What is your mic in your screenshot? When I convert it to decimal, it seems to be sth. like 428068396, but the mic in the log is more like 4087081005. When I check the mic from the log, I get sth. like 0xF39BE82D which I cannot see anywhere in your posted screenshot.

Marius

NilsMinor commented 4 years ago

Hi Marius,

would it help if I share all my code ? I will create a public git repo if I am ready with the ionic plugin but I can do this before in an unstable version of course ^^

The print outs from screenshot like mic and encryptedData are from the console.logs from the code above that performs the message encryption with your nounces. For testing I am using the keys, ids and nonces from your first node. The mic is calculated using the data that was xored before and keystream2 but the key stream is already wrong. I tried to implement this the same way like the Android example. The keystream1 is correct but I do not find the difference to the keystream2 calculation.

This lines from your code :

[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1B:01:00:02:00:0E:75:87:87:86:F8:76:04 (13) with nonce 4087081004
[MeshAccessConnection.cpp@642 ERROR]: Encryption Keystream 85:39:E9:56:01:F3:DA:15:E6:0C:F5:C2:6C:F6:A0:5E
[MeshAccessConnection.cpp@674 ERROR]: MIC nonce 4087081005 produces Keystream 7A:DE:23:6E:FF:9B:E6:A1:41:25:97:52:D8:AF:C6:9F

My kestream1 is 85 39 E9 56 1 F3 DA 15 E6 C F5 C2 6C F6 A0 5E using 4087081004 that's fine to me. But using 4087081005 in the second step generates E5 A4 7B 7C C0 E0 97 84 BC 6A 9B EC 2 51 3E E as keystream2 but it should be 7A:DE:23:6E:FF:9B:E6:A1:41:25:97:52:D8:AF:C6:9F correct? Or do I understand this in a wrong way? Thanks for your support !

mariusheil commented 4 years ago

Hi,

I probably will not have enough time to set up your code and test it through. Do you have the CherrySim running? If not, I think it would be very helpful for you to set it up. If you are on windows, it should be quite trivial by using Visual Studio, it also works on other systems. We have a guide in our documentation. Then you would be able to debug the whole connection handshake process between two nodes in the CherrySimTester. (You have to choose the CherrySimTester launch configuration, not the runner).

I have written a test for you which looks like this:

TEST(TestMeshAccessModule, TestConnectWithNetworkKey)
{
    //Set up a test with two nodes that are close together
    CherrySimTesterConfig testerConfig = CherrySimTester::CreateDefaultTesterConfiguration();
    testerConfig.verbose = true;
    SimConfiguration simConfig = CherrySimTester::CreateDefaultSimConfiguration();
    simConfig.terminalId = 0;
    simConfig.preDefinedPositions = { {0.5, 0.5},{0.6, 0.6} };
    simConfig.nodeConfigName.insert({ "github_nrf52", 2 });
    simConfig.SetToPerfectConditions();

    CherrySimTester tester = CherrySimTester(testerConfig, simConfig);

    //Enable some logging to be able to better understand the MeshAccessConnection
    tester.sim->findNodeById(1)->gs.logger.enableTag("MACONN");
    tester.sim->findNodeById(2)->gs.logger.enableTag("MACONN");
    tester.sim->findNodeById(1)->gs.logger.enableTag("MAMOD");
    tester.sim->findNodeById(2)->gs.logger.enableTag("MAMOD");

    // Change default network id of node 2 so it will not automatically connect to node 1
    tester.sim->nodes[1].uicr.CUSTOMER[9] = 123;

    tester.Start();

    //Tell node 1 to connect to node 2 using a mesh access connection and the network key (2)
    //NetworkKey is not given here as both nodes have the same networkKey stored because of the test setup
    tester.SendTerminalCommand(1, "action this ma connect 00:00:00:02:00:00 2");

    // We should initially get a message that gives us info about the cluster, size 2 and 1 hop to sink
    tester.SimulateUntilMessageReceived(5000, 2, "-- TX Handshake Done");
}

You have to copy this to the bottom of TestMeshAccessConnection.cpp and then change one line in CherrySimTester.cpp (around line 95) to this:

::testing::GTEST_FLAG(filter) = "*TestConnectWithNetworkKey*";

This will make sure that only this one test will get executed.

You can then comment in some of the logs in e.g. MeshAccessConnection::GenerateSessionKey to get some output for the key generation. Make sure to change the logtag from ERROR to MACONN as the Simulator will otherwhise run into a breakpoint and will complain about the ERROR logtag. I have added some more logs for you with the cleartext of the keystreams.

If you let this run through, it should look sth. like this:

0000000:1:[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection
0000000:1:[GAPController.cpp@112 CONN]: pairing
0000000:1:[MeshAccessConnection.cpp@203 MACONN]: Trying to connect
0000000:1:[FlashStorage.cpp@303 FLASH]: Flash operation success
0000000:2:[FlashStorage.cpp@303 FLASH]: Flash operation success
0000004:2:[GAPController.cpp@125 C]: Connected device
0000004:2:[MeshAccessModule.cpp@346 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:17:16:12:FE:03:00:0B:00:09:01:00:00:00:00:00:00:01:00:00:00:00:00:00:00, len 31
0000004:2:[ResolverConnection.cpp@47 RCONN]: New Resolver Connection
0000004:2:[BaseConnection.cpp@612 CONN]: Incoming connection 0 connected
0000004:1:[GAPController.cpp@125 C]: Connected device
0000004:1:[BaseConnection.cpp@614 CONN]: Outgoing connection 0 connected
0000004:1:[GATTController.cpp@56 GATTCTRL]: Starting Service discovery 0001 type 0, connHnd 1
0000014:1:[GATTController.cpp@68 GATTCTRL]: DB Discovery Event
0000014:1:[MeshAccessConnection.cpp@1141 MACONN]:Service discovered 1
0000014:1:[MeshAccessConnection.cpp@1149 MACONN]:Found service
0000014:1:[MeshAccessConnection.cpp@1154 MACONN]:Found rx char 2
0000014:1:[MeshAccessConnection.cpp@1149 MACONN]:Found service
0000014:1:[MeshAccessConnection.cpp@1161 MACONN]:Found tx char 4 with cccd 5
0000014:1:[MeshAccessConnection.cpp@221 MACONN]: Registering for notifications
0000014:1:[MeshAccessConnection.cpp@239 MACONN]: -- TX Start Handshake
0000014:1:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 1 to 2001
0000014:1:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000016:2:[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
0000016:2:[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
0000016:2:[MeshConnection.cpp@83 MACONN]: MeshConnResolver
0000016:2:[ResolverConnection.cpp@61 RCONN]: Resolving Connection with received data
0000016:2:[ConnectionManager.cpp@227 RCONN]: numConnTypeResolvers 2
0000016:2:[MeshConnection.cpp@83 MACONN]: MeshConnResolver
0000016:2:[MeshAccessModule.cpp@346 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:17:16:12:FE:03:00:0B:00:09:01:00:00:00:00:00:00:01:00:00:00:00:00:00:00, len 31
0000016:2:[MeshAccessConnection.cpp@74 MACONN]: New MeshAccessConnection
0000016:2:[BaseConnection.cpp@612 CONN]: Incoming connection 0 connected
0000016:2:[MeshAccessConnection.cpp@269 MACONN]: -- TX ANonce, fmKeyId 2
0000016:2:[MeshAccessConnection.cpp@518 MACONN]: Using network key
0000016:2:[MeshAccessConnection.cpp@550 MACONN]: LongTerm Key is 04:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
0000016:2:[MeshAccessConnection.cpp@565 MACONN]: SessionKeyCleartext 01:00:97:3F:E5:D8:35:90:85:32:00:00:00:00:00:00
0000016:2:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 2 to 2002
0000016:2:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000016:2:[MeshAccessModule.cpp@346 MAMOD]: Broadcasting mesh access 02:01:06:03:03:12:FE:17:16:12:FE:03:00:0B:00:09:01:00:00:00:00:00:00:01:00:00:00:00:00:00:00, len 31
0000018:1:[MeshAccessConnection.cpp@329 MACONN]: -- TX SNonce, anonce 847614005
0000018:1:[MeshAccessConnection.cpp@518 MACONN]: Using network key
0000018:1:[MeshAccessConnection.cpp@550 MACONN]: LongTerm Key is 04:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@565 MACONN]: SessionKeyCleartext 01:00:97:3F:E5:D8:35:90:85:32:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@518 MACONN]: Using network key
0000018:1:[MeshAccessConnection.cpp@550 MACONN]: LongTerm Key is 04:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@565 MACONN]: SessionKeyCleartext 01:00:6D:FD:47:DA:3D:00:9E:84:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@609 MACONN]: EncrKey: FA:3E:86:95:5A:82:ED:2C:38:28:77:48:E3:99:39:CB
0000018:1:[MeshAccessConnection.cpp@610 MACONN]: DecrKey: 08:22:32:AB:E1:20:28:1D:FC:07:AB:A2:66:51:5B:00
0000018:1:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 1 to 2001
0000018:1:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000018:1:[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1B:01:00:02:00:6D:FD:47:DA:3D:00:9E:84 (13) with nonce 847614005
0000018:1:[MeshAccessConnection.cpp@638 MACONN]: Encryption Keystream cleartext 97:3F:E5:D8:35:90:85:32:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@646 MACONN]: Encryption Keystream A4:2C:73:00:61:0A:74:9C:78:BF:D4:F2:B2:EC:F5:0C
0000018:1:[MeshAccessConnection.cpp@661 MACONN]: Encryption Keystream 2 cleartext 97:3F:E5:D8:36:90:85:32:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@670 MACONN]: Encryption Keystream 2 D8:71:DB:5C:29:CE:D6:29:9B:5E:FE:24:1F:68:BE:2F
0000018:1:[MeshAccessConnection.cpp@699 MACONN]: Encrypted as BF:2D:73:02:61:67:89:DB:A2:82:D4:6C:36:5B:57:71:75 (17)
0000018:1:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 1 to 0
0000018:1:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000018:1:[MeshAccessConnection.cpp@627 MACONN]: Encrypting 17:01:00:00:00:00:00:00:00:01:00:FF:FF:01 (14) with nonce 847614007
0000018:1:[MeshAccessConnection.cpp@638 MACONN]: Encryption Keystream cleartext 97:3F:E5:D8:37:90:85:32:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@646 MACONN]: Encryption Keystream FC:B5:BF:CC:0D:26:46:79:2B:3D:66:9C:F6:EE:44:F6
0000018:1:[MeshAccessConnection.cpp@661 MACONN]: Encryption Keystream 2 cleartext 97:3F:E5:D8:38:90:85:32:00:00:00:00:00:00:00:00
0000018:1:[MeshAccessConnection.cpp@670 MACONN]: Encryption Keystream 2 E8:70:28:66:8E:E6:DB:B2:0B:F9:13:8B:44:C9:76:2F
0000018:1:[MeshAccessConnection.cpp@699 MACONN]: Encrypted as EB:B4:BF:CC:0D:26:46:79:2B:3C:66:63:09:EF:C2:F0:6F:D8 (18)
{"nodeId":1,"type":"ma_conn_state","module":10,"requestHandle":0,"partnerId":2001,"state":4}
0000018:1:[MeshAccessConnection.cpp@388 MACONN]: Handshake done as Central
0000018:2:[MeshAccessConnection.cpp@707 MACONN]: Decrypting BF:2D:73:02:61:67:89:DB:A2:82:D4:6C:36:5B:57:71:75 (17) with nonce 847614005
0000018:2:[MeshAccessConnection.cpp@765 MACONN]: Decrypted as BF:2D:73:02:61:67:89:DB:A2:82:D4:6C:36 (13) micValid 1
0000018:2:[MeshAccessConnection.cpp@396 MACONN]: -- TX Handshake Done, snonce 0
0000018:2:[MeshAccessConnection.cpp@518 MACONN]: Using network key
0000018:2:[MeshAccessConnection.cpp@550 MACONN]: LongTerm Key is 04:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@565 MACONN]: SessionKeyCleartext 01:00:6D:FD:47:DA:3D:00:9E:84:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@609 MACONN]: EncrKey: 08:22:32:AB:E1:20:28:1D:FC:07:AB:A2:66:51:5B:00
0000018:2:[MeshAccessConnection.cpp@610 MACONN]: DecrKey: FA:3E:86:95:5A:82:ED:2C:38:28:77:48:E3:99:39:CB
0000018:2:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 2 to 2002
0000018:2:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000018:2:[MeshAccessConnection.cpp@627 MACONN]: Encrypting 1C:02:00:01:00:00 (6) with nonce 2224947261
0000018:2:[MeshAccessConnection.cpp@638 MACONN]: Encryption Keystream cleartext 6D:FD:47:DA:3D:00:9E:84:00:00:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@646 MACONN]: Encryption Keystream 9B:25:7E:B8:F2:71:BC:FF:F6:19:2F:29:AA:A2:45:27
0000018:2:[MeshAccessConnection.cpp@661 MACONN]: Encryption Keystream 2 cleartext 6D:FD:47:DA:3E:00:9E:84:00:00:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@670 MACONN]: Encryption Keystream 2 B9:30:17:A6:DB:04:E0:F7:A7:35:92:86:38:1B:EA:C1
0000018:2:[MeshAccessConnection.cpp@699 MACONN]: Encrypted as 87:27:7E:B9:F2:71:F6:64:21:E5 (10)
0000018:2:[MeshAccessConnection.cpp@853 MACONN]: MA SendData from 2 to 0
0000018:2:[MeshAccessModule.cpp@654 MACONN]: Message auth is 1
0000018:2:[MeshAccessConnection.cpp@627 MACONN]: Encrypting 17:02:00:00:00:00:00:00:00:01:00:FF:FF:01 (14) with nonce 2224947263
0000018:2:[MeshAccessConnection.cpp@638 MACONN]: Encryption Keystream cleartext 6D:FD:47:DA:3F:00:9E:84:00:00:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@646 MACONN]: Encryption Keystream 91:82:5B:BD:A8:24:F9:07:53:05:06:59:66:B2:7F:C6
0000018:2:[MeshAccessConnection.cpp@661 MACONN]: Encryption Keystream 2 cleartext 6D:FD:47:DA:40:00:9E:84:00:00:00:00:00:00:00:00
0000018:2:[MeshAccessConnection.cpp@670 MACONN]: Encryption Keystream 2 6F:1D:01:CA:ED:12:7A:F9:FE:3F:91:55:D1:8E:A3:D4
0000018:2:[MeshAccessConnection.cpp@699 MACONN]: Encrypted as 86:80:5B:BD:A8:24:F9:07:53:04:06:A6:99:B3:0D:DE:33:E4 (18)
0000018:2:[MeshAccessConnection.cpp@443 MACONN]: Handshake done as Peripheral

Next, you can set some breakpoints in the following Methods:

This should give you a perfect overview about what is happening with the encryption step by step. Some methods will be called while node 1 is simulated, others will be called while node 2 is simulated, but this will be transparent for you and you will also get the complete log with the nodeId always prefixed in the beginning of the line. Here is an exemplary log from my simulation (might be different for you as I was using a different codebase). But you will always get the exact same log with the same numbers if you restart the simulation, if you want to get a different simulation, you can change the seed of the simulator.

Marius

NilsMinor commented 4 years ago

Hi @mariusheil wow, thanks for providing the cherrysim example. I will test this in the near time but I used cherrysim not before so it might take some time to get this up and run.

As I will open source the ionic library I am trying to learn on how to publish such kind of library as I never did this before ^^ I uploaded the encryption manager code here https://github.com/NilsMinor/ngx-ble-mesh/blob/master/src/encryption-manager.ts

I think that your logs will help me to find out what I am doing wrong with encrypting the message. I run my code only as test right now so I do not need to connect with a smartphone to a node as I am only use your nodeIDs, keys, and data from your first example logs. Thanks for your support :)

NilsMinor commented 4 years ago

Hi @mariusheil , i can't figure out what I am making wrong with my message encryption. I run a static test so without any bleeding communication just with your example nodeID 1 and your example key 0x11, 0x11 .... and the example nonces (3862350040, 4087081004).

When I run my code with the example data (1B:01:00:02:00:0E:75:87:87:86:F8:76:04 (13)) and perform an encryption (see code here --> https://github.com/NilsMinor/ngx-ble-mesh/blob/188a081dcc41bb25626eded6bbb6e1ef75b7a4fb/src/encryption-manager.ts#L100 ) I get this output

Angular is running in development mode. Call enableProdMode() to enable production mode. core.js:26543
sessionEncryptionKey  (16) : 7B 10 EE 29 F4 66 11 3B 1B FD C6 75 EB EF 52 31 encryption-manager.ts:41:14
target mic :  (4) : 7A DE 23 6E encryption-manager-test.ts:99:10
target message  :  (17) : 9E 38 E9 54 1 FD AF 92 61 8A D B4 44 7A DE 23 6E encryption-manager-test.ts:100:10
using nonce  4087081004 encryption-manager.ts:110:12
keystream1 (16) : 85 39 E9 56 1 F3 DA 15 E6 C F5 C2 6C F6 A0 5E encryption-manager.ts:112:12
using nonce  4087081005 encryption-manager.ts:120:12
keystream2 (16) : E5 A4 7B 7C C0 E0 97 84 BC 6A 9B EC 2 51 3E E encryption-manager.ts:125:12
calculated mic :  (4) : 2B B8 1B E8 encryption-manager.ts:134:12
encryptied message  :  (17) : 9E 38 E9 54 1 FD AF 92 61 8A D B4 68 2B B8 1B E8 encryption-manager-test.ts:103:10
encrypted message generation was wrong encryption-manager-test.ts:109:10

I create a second keystream (keyStream2) using my sessionEncryptionKey and my incremented encryptionNounce. Then I xor the cleartext with keystream2 but the mic is not 7A DE 23 6E like in your example. The keyStream2 is already wrong and I have no clue why. Sorry for writing you again with no progress. You might spot the mistake in my encryptMessage function.

Thanks, Nils

mariusheil commented 4 years ago

Hi,

I will look into this but I will not have time today and probably not tomorrow. This would be really easy to debug with the Simulator. What OS are you using? I guess I will debug this through once I have the time and write down the whole procedure with example data and add that to the Mesh access Documentation as this will also help others a lot.

In the meantime try to increment the nonce twice, increment it once for the payload and a second time for generating the keystream 2. This is just guessing, but I remember the nonce being incremented twice for a packet, so check the code again if you can spot this. There is some part where it is incremented and than decremented again as it must wait for the packet to be sent properly, ignore that decrement as you do not have to take care of lost packets.

Marius

NilsMinor commented 4 years ago

Hi @mariusheil, i am using OS X for development. As I am working on the fruity-mesh ionic library in my free-time this is not time critical so I am thankful for any support of you :)

I am already doing a second counter increment.(https://github.com/NilsMinor/ngx-ble-mesh/blob/188a081dcc41bb25626eded6bbb6e1ef75b7a4fb/src/encryption-manager.ts#L100 ) I increment after the payload so generating keystream2 is done using the incremented counter value but my key is not 7A:DE:23:6E:FF:9B:E6:A1:41:25:97:52:D8:AF:C6:9F as it should be right?

mariusheil commented 4 years ago

Hi,

I have written a lot of documentation with example data, which should be helpful for everybody trying to implement the MeshAccessConnection Handshake. I've attached it here and it will be part of our documentation once we release again. Mesh Access Connection.pdf

Marius

NilsMinor commented 4 years ago

Hi @mariusheil ,

I am making progress (haha). I was able to perform a valid message encryption from your first example and got 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68:7A:DE:23:6E ans encrypted message (it is from your first example). I tried to run a second test from your pdf example (with different data and key ...).

You get in your pdf encrytion example the following result 79:65:A5:B6:A6:A7:58:89:0D:E8:77:ED:DC:CA:CA:47:57. When I run my code I get 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC E0 F1 7E 7B. So my cipher text is fin but my MIC is E0 F1 7E 7B instead of CA CA 47 57 so are you sure with the example result from the pdf?

This is my log just for your info:

sessionEncryptionKey  (16) : 3 1C BD BA 73 42 FD B0 95 13 81 AB 97 94 8C D9 encryption-manager.ts:47:20
data (16) : 1B 1 0 D1 7 FC D3 B8 64 AD F E8 19 0 0 0 encryption-manager.ts:114:16
keystream1 (16) : 62 64 A5 B4 A6 5B 8B 31 69 45 78 5 C5 26 69 E4 encryption-manager.ts:122:16
ciphertext  (16) : 1B 1 0 D1 7 FC D3 B8 64 AD F E8 19 0 0 0 encryption-manager.ts:124:16
encryptionNounce  (16) : 1D 4C FA 4E 33 19 68 2A 0 0 0 0 0 0 0 0 encryption-manager.ts:132:16
keystream2  (16) : 4 14 36 4B 49 93 9C 40 68 49 7A 55 73 AB E7 73 encryption-manager.ts:135:16
ciphertext  (16) : 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC 0 0 0 encryption-manager.ts:137:16
ciphertext xored (16) : 7D 71 93 2E E8 34 C4 C9 65 A1 D B8 AF AB E7 73 encryption-manager.ts:142:16
calculated mic :  (4) : E0 F1 7E 7B encryption-manager.ts:146:16
encryptied message     :  (17) : 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC E0 F1 7E 7B encryption-manager-test.ts:106:12
mariusheil commented 4 years ago

Hi,

yes I am pretty sure as this was the output the simulator was giving me. You can get the same by either setting up the simulator or you can program the firmware on two nodes and hardcore the initial anonce and snonce instead of using the random number generator. Then you would also be able to add logs.

Marius

Nils Minor notifications@github.com schrieb am Do., 27. Aug. 2020, 21:02:

Hi @mariusheil https://github.com/mariusheil ,

I am making progress (haha). I was able to perform a valid message encryption from your first example and got 9E:38:E9:54:01:FD:AF:92:61:8A:0D:B4:68:7A:DE:23:6E ans encrypted message (it is from your first example). I tried to run a second test from your pdf example (with different data and key ...).

You get in your pdf encrytion example the following result 79:65:A5:B6:A6:A7:58:89:0D:E8:77:ED:DC:CA:CA:47:57. When I run my code I get 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC E0 F1 7E 7B. So my cipher text is fin but my MIC is E0 F1 7E 7B instead of CA CA 47 57 so are you sure with the example result from the pdf?

This is my log just for your info:

sessionEncryptionKey (16) : 3 1C BD BA 73 42 FD B0 95 13 81 AB 97 94 8C D9 encryption-manager.ts:47:20 data (16) : 1B 1 0 D1 7 FC D3 B8 64 AD F E8 19 0 0 0 encryption-manager.ts:114:16 keystream1 (16) : 62 64 A5 B4 A6 5B 8B 31 69 45 78 5 C5 26 69 E4 encryption-manager.ts:122:16 ciphertext (16) : 1B 1 0 D1 7 FC D3 B8 64 AD F E8 19 0 0 0 encryption-manager.ts:124:16 encryptionNounce (16) : 1D 4C FA 4E 33 19 68 2A 0 0 0 0 0 0 0 0 encryption-manager.ts:132:16 keystream2 (16) : 4 14 36 4B 49 93 9C 40 68 49 7A 55 73 AB E7 73 encryption-manager.ts:135:16 ciphertext (16) : 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC 0 0 0 encryption-manager.ts:137:16 ciphertext xored (16) : 7D 71 93 2E E8 34 C4 C9 65 A1 D B8 AF AB E7 73 encryption-manager.ts:142:16 calculated mic : (4) : E0 F1 7E 7B encryption-manager.ts:146:16 encryptied message : (17) : 79 65 A5 65 A1 A7 58 89 D E8 77 ED DC E0 F1 7E 7B encryption-manager-test.ts:106:12

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mwaylabs/fruitymesh/issues/139#issuecomment-682134986, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABM62NA7UX3UKUUKJOC2FX3SC2UUTANCNFSM4NVZPRBA .

NilsMinor commented 4 years ago

Hi @mariusheil , just wanted to let you know that you were right, I made a mistake with the zero padding. So encryption is working now and I get micValid 1 so the peripheral accepts my message :D I now have to do the decryptMessage but I think I will get this done with your example and PDF (when I have time for it of course ^^) Best regards, Nils

NilsMinor commented 4 years ago

Hi @mariusheil , so encryption is working fine yet ! Thanks a lot for your support. The code will be maintained in this repo when it is ready and will be part of npm (when I get this done) so everyone could easily install it using npm.