robertklep / nefit-easy-core

Core functionality to implementation communications with Nefit/Bosch backend.
MIT License
21 stars 4 forks source link

Password and access keys for other Bosch products? #12

Closed andreassolberg closed 6 years ago

andreassolberg commented 6 years ago

I'm trying to debug communication with the Bosch backend for a heat pump Bosch Compress 7000 AW. The protocol seems to be more or less identical what this software implements.

However, I'm struggelig with decrypting the messages. I'm not sure what is the accessKey and password for the heat pump. The serial is OK I think. I have set one password when initializing the app, may be that one is the password? But then what is the accessKey? Could it be the QR code on the pump? That is a long digit number, should it be translated into binary/hex? All help is welcome! Thanks...

robertklep commented 6 years ago

The Nefit Easy thermostat is shipped with two codes: the serial number and the access code. The user adds their password when they initialize the device for the first time.

The access code for the Easy is a 16-character code. It's not hex and contains both upper- and lowercase characters (so I don't think it's a base-?? representation of a long number). It's presented as such, not as a QR code.

The access key and the password are used, in combination with a fixed "secret" in the Nefit Easy app, to encrypt/decrypt messages. The serial isn't used in that process.

I assume that you can control the pump with an app? If so, how do you "pair" the app with the pump? Which data do you have to enter? That might provide a clue which values might be getting used in the encryption/decryption process.

GitDuff commented 6 years ago

Sorry to drag up an old "issue" but I was trying with with another Bosch product, under the swedish brand IVT, which is similar to the Bosch mentioned before.

The api uses wa2-mz36-qrmzh6.bosch.de, but I can't get the server to authentic ok. On the unit I have a "Loginname", "Passwort" and QR code. I could register the unit on the IVT Anywhere app with the QR code, or the Loginname and password, after which I assign my own password.

The loginname seem to be based on the serial of the unit 9 numeric digits, and the "passwort" is 16 digits in 4 digit chunks separated by "-" XXXX-XXXX-XXXX-XXXX where X is a mix of numeric digits and upper and lower case letters.

I've tried with: node v8.12.0 npm 6.4.1 easy-server 5.0.2 and just for interest the earlier node v6.0.0 npm 3.8.6 easy-server 5.0.2

and got the same "XMPP authentication failure"

Even tried removal of the "-" in the access-key/passwort

I've also attached the com.bosch.tt.IVT_2018-06-28.apk file (renamed to zip) if that helps Any help would be appreciated.

com.bosch.tt.IVT_2018-06-28.zip

robertklep commented 6 years ago

@GitDuff I've recently taken a look at the IVT Anywhere app for a Norwegian user, but in the end we didn't get very far.

We did determine that the username that is being used is contact_SERIAL (where SERIAL is replaced by the 9-digit serial number), but I now realise that the current version of nefit-easy-core hardcodes certain string prefixes that are required for the Nefit Easy, but won't work with IVT (because it uses a different prefix).

If you know how to modify a Node module, you can edit the file nefit-easy-core/lib/index.js, specifically these lines:

const ACCESSKEY_PREFIX   = 'Ct7ZR03b_';
const RRC_CONTACT_PREFIX = 'rrccontact_';
const RRC_GATEWAY_PREFIX = 'rrcgateway_';

Start by changing the first two to this:

const ACCESSKEY_PREFIX   = '';
const RRC_CONTACT_PREFIX = 'contact_';

And see what that does.

GitDuff commented 6 years ago

Cheers, I'll try that and see if I get any further.

GitDuff commented 6 years ago

Still "XMPP authentication failure"

robertklep commented 6 years ago

Did you also try removing the dashes from the password? Other than that, I can't be of more help: I don't have an appliance that uses the IVT Anywhere app so I can't do any testing or network sniffing :(

GitDuff commented 6 years ago

Yeah, Tried that also. Seems like the IVT app is in essence identical to the Bosch EasyRemote app since I can use that also without any issues. I'll try and connect a laptop with wireshark between the IVT Gateway and router and see if I can see anything obvious on the packets regarding the prefixes.

robertklep commented 6 years ago

The Norwegian user also provided some Wireshark traces, which is how I found out which username was being used. But password isn't sent in the clear (thankfully ;), and at least for the Nefit app, the password is also prefixed with a string before being hashed. I haven't been able to find out it the same applies to the IVT/EasyRemote apps, though.

If you're interested in a decompiled version of the app, let me know. I have to warn it's obfuscated, so not very clear, but nonetheless it might be helpful if you can read code :)

GitDuff commented 6 years ago

Hi, Code is no probs :) its my day job too, granted Erlang. Which is the reason I ended up here. The heating system is the final part to integrate in my own home automation software.

I scanned through the apk of the NefitEasy app and can see the "rrcgateway" "rrccontact" and "Ct7ZR03b_" visible in the classes.dex file. Unfortunately I couldnt see an equivalent in the classes.dex file in the IVT app, wishful thinking it might be so simple.

Absolutely interesting to see the decompiled version of the app.

Thanks Alan

robertklep commented 6 years ago

Cool :) If you can send me an e-mail (robert AT klep DOT name), I'll send you the decompiled app.

GitDuff commented 6 years ago

done :+1:

andreassolberg commented 6 years ago

A while since I looked at this last time, I did not succeed then. But I am very interested in solving this.

The content of the communication with wa2-mz36-qrmzh6.bosch.de seemed to be a simple REST based protocol wrapped in XMPP. The simple REST protocol is exposed directly at the heat pump from the local network. If I remember correctly this protocol is stateless, and there is no authentication, however the response was encrypted using aes-256-ecb. I did create a simple script to try to decrypt the response based upon this library. But I have not yet succeeded.

If the logic and code is correct, I guess the variables are prefixes, and the secret magic key.

I use an iOS app called Bosch ProControl. I have decompiled it, but it seems that the interesting part may be within an SO file. And I have no experience with debugging these things further:

[andreas@andreas-solberg:com.bosch.tt.ProControl-v3.2.4_source_from_JADX]$ grep -ri wa2-mz36-qrmzh6.bosch.de *
Binary file lib/armeabi-v7a/libcomlib-android.so matches
Binary file lib/x86/libcomlib-android.so matches
Binary file lib/arm64-v8a/libcomlib-android.so matches
Binary file lib/armeabi/libcomlib-android.so matches
robertklep commented 6 years ago

@andreassolberg for IVT and Nefit, XMPP authentication is required, and on top of that, there's an additional layer of encryption that is exactly how you describe (a REST-ish protocol over XMPP where request and response data is encrypted using AES256).

IVT uses different authentication and encryption mechanisms than Nefit, and it sounds like your heat pump uses yet another mechanism. For IVT, what really helped was decompiling an older version of the IVT app, which is much less obfuscated than current versions. Perhaps the same applies to the ProControl app too (I'm also using jadx).

andreassolberg commented 6 years ago

If you connect to wa2-mz36-qrmzh6.bosch.de you have to authenticate, some XMPP SASL variant.

However, if I perform a simple GET call directly to the heat pump from the local network, I get an encrypted response. I tried to wireshark this today, by checking of the iOS app to perform a local connection rather than going via bosch cloud service.

The request goes like this (unauthenticated):

GET /dhwCircuits/dhw1/actualTemp HTTP/1.0
User-Agent: TeleHeater
Connection: Close
Host: 10.0.0.15

and the response is encrypted (at least looks encrypted):

200 OK
Content-Type: application/json

DRWPn5EsglvzkwzJI0xQmPTPW0bkHAzKfN9KfvyMqiSaT9QLjFElsBBgDSyhVHeO2/7HdoB9N9OTNIT6JqynIQqWYrz4gc4Jr8/No9Vb8gpaJiopRPY+IhRDnvqRmp/khtrI17FkBv+/iADI+BWqpDuXl11gHoQnI5ZMoshPZpasBedRxcLm2tx+qqotU7LPjtRo4c1gbS9+i0xNxI31veIsoA49Gz3l8d3C5JWgseQ=
robertklep commented 6 years ago

Looks like you could get this working using this Node.js module that I uploaded to Github earlier today: https://github.com/robertklep/bosch-xmpp

Try the IVT example with the correct credentials. FWIW, this doesn't communicate with the device directly, but over XMPP (basically because all this code is based on my initial work for the Nefit Easy device, which doesn't expose an HTTP server directly).

At least for IVT devices, decryption works.

andreassolberg commented 6 years ago

WOW IT WORKS! Thank you!!!

[andreas@andreas-solberg:bosch-xmpp]$ node bosch-example.js 
{
  "id": "/heatSources/returnTemperature",
  "type": "floatValue",
  "writeable": 0,
  "recordable": 0,
  "value": 29.4,
  "unitOfMeasure": "C",
  "state": [
    {
      "open": -3276.8
    },
    {
      "short": 3276.7
    }
  ]
}
robertklep commented 6 years ago

Nice!

What type of device (make and model) are you communicating with? I'm trying to compile a list of devices (or device ranges) that the code works with :)

GitDuff commented 6 years ago

Must have a try at the local api also...

On 23 Sep 2018, at 21:35, Robert Klep notifications@github.com wrote:

Nice!

What type of device (make and model) are you communicating with? I'm trying to compile a list of devices (or device ranges) that the code works with :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

andreassolberg commented 6 years ago

What type of device (make and model) are you communicating with?

Bosch Compress 7000i AW

robertklep commented 6 years ago

Closing this issue.

For those interested: I added a command line interface to bosch-xmpp that will make it easier to interface with your devices. More info here: https://github.com/robertklep/bosch-xmpp#command-line-interface

GitDuff commented 6 years ago

Thanks for the help... Works great.

Marko-Rintamaki commented 5 years ago

Hi.

if you still need a key then i have the "vendor key" or get it https://github.com/hansliss/regofetcher i did the program c# to read and write to the rego2000 module I believe "vendor key" is the same in other modules. Bosch, IVT, et al.

-Marko

robertklep commented 5 years ago

Thanks @Marko-Rintamaki :)

That is indeed the same key as I'm using for IVT (here).

yunux commented 5 years ago

WOW IT WORKS! Thank you!!!

[andreas@andreas-solberg:bosch-xmpp]$ node bosch-example.js 
{
  "id": "/heatSources/returnTemperature",
  "type": "floatValue",
  "writeable": 0,
  "recordable": 0,
  "value": 29.4,
  "unitOfMeasure": "C",
  "state": [
    {
      "open": -3276.8
    },
    {
      "short": 3276.7
    }
  ]
}

Hi @andreassolberg, @robertklep I'm trying to retrieve values from my new Bosch 7000i using bosch-xmpp on my local network. I seem to have trouble authenticating. This is what I'm trying:

const{IVTClient} = require('bosch-xmpp');

const client = IVTClient({
    host : '10.180.1.20',
    port: 5222,
    serialNumber : '2600-818-000036-8738208984',
    accessKey    : 'xxxxxxxxx',
    password     : 'XXXX-XXXX-XXXX-XXXX'
});

client.connect();

console.log('This example is different!');
try {
    console.log('client = ',client);
    console.log('%j', client.get('/gateway/versionFirmware'));
    console.log('%j', client.get('/heatSources/returnTemperature'));
} catch(e) {
    console.log('error')
  console.error(e.stack || e);
}
client.end();

This is the result:


yunux@angkor:~/Documents/src/bosch-xmpp-test$ node connect.js
{"isFulfilled":false,"isRejected":false}
{"isFulfilled":false,"isRejected":false}
Unhandled rejection Error: MAX_RETRIES_REACHED
    at queueMessage.catch.e (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bosch-xmpp/lib/base-client.js:179:51)
    at tryCatcher (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:690:18)
    at _drainQueueStep (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:138:12)
    at _drainQueue (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues [as _onImmediate] (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:17:14)
    at processImmediate (timers.js:632:19)

Unhandled rejection Error: MAX_RETRIES_REACHED
    at queueMessage.catch.e (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bosch-xmpp/lib/base-client.js:179:51)
    at tryCatcher (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/promise.js:690:18)
    at _drainQueueStep (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:138:12)
    at _drainQueue (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues [as _onImmediate] (/home/yunux/Documents/src/bosch-xmpp-test/node_modules/bluebird/js/release/async.js:17:14)
    at processImmediate (timers.js:632:19)

Unhandled rejection Error: connect ETIMEDOUT 10.180.1.20:5222
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1083:14)

I'm very new to node.js, xmpp, and related so please bear with me. Am I missing any information, what port should I use? Any pointers are greatly appreciated. @andreassolberg if you can share some code that made it work for you, it would be really helpful. Thanks!
robertklep commented 5 years ago

@yunux it's probably the easiest if you base your code on the bosch-xmpp example code.

Try this:

const { IVTClient } = require('bosch-xmpp');

const client = IVTClient({
  serialNumber : '2600-818-000036-8738208984',
  accessKey    : 'xxxxxxxxx',
  password     : 'XXXX-XXXX-XXXX-XXXX'
});

client.connect().then(() => {
  return Promise.all([
    client.get('/gateway/versionFirmware'),
    client.get('/heatSources/returnTemperature'),
  ]);
}).then(responses => {
  console.log('%j', responses);
}).catch(e => {
  console.error(e.stack || e);
}).finally(() => {
  client.end();
});

Some remarks:

yunux commented 5 years ago

Thanks @robertklep . Very helpful. Thanks for putting up with my ignorance :) Now I get this:

yunux@angkor:~/Documents/src/bosch-xmpp-test$ node example.js
XMPP authentication failure

I must have either serial number, accesskey or password wrong although I have tried several combinations.

robertklep commented 5 years ago

@yunux try removing all hyphens (-) from the access key and/or serial number. For the XMPP authentication part, only the serial number and access key are used, the password is only used for data encryption/decryption.

yunux commented 5 years ago

Thanks @robertklep. I tried that already without any luck.

robertklep commented 5 years ago

@yunux if you're okay with sharing your credentials with me (over direct e-mail: robert AT klep DOT name), I'll take a look if you want.

hansliss commented 3 years ago

On my IVT, there's a 32-byte binary vendor key which is embedded in the app, a device password on the format "aaaa-aaaa-aaaa-aaaa", that's printed on the IP module, and a user password that can be set on the front panel.

The actual encryption key is generated from by first calculating the MD5 of the device password minus hyphens, prepended to the binary vendor key, and then calculating the MD5 of the binary vendor key prepended to the user password, and then concatenating the MD5 sums.

You can find the vendor key for the IVT in my sample config file on https://github.com/hansliss/regofetcher