Bridge Beta FW 1.22.1 / 2.14.0 with new Encrypted Bridge HTTP API token

Introduction

With the new Beta firmware version 1.22.1 / 2.14.0 Nuki introduces the new encrypted token for the Bridge API. This new feature brings the security of the API access onto the next level and is available as Beta version from now on. That allows to upgrade and verify integrations already before the public release, which is planned for July 2022.

The hashed token method is deprecated by the introduction of this new method but will remain available in the API in order to not break existing integrations until at least end of 2022.

Link to latest Nuki Bridge HTTP API documentation
https://developer.nuki.io/page/nuki-bridge-http-api-1-13/4

Technical details

The idea is to calculate an encrypted token which is only valid for the execution of a single HTTP command. This token is calculated as following:

  1. Compute secret key by calculating the SHA256 from the API token
  2. Random 24 byte nonce is created
  3. The crypted token (=ctoken) is derived from xsalsa20poly1305 encryption of the current timestamp and a random number with the secret key and the nonce from above

This ctoken is then sent in hexadecimal, which results in the fact that information is no longer sent in plaintext (such as the date, random number, API token).

The Bridge implements a similar methodology for decryption. Following security measures and handlings have been introduced on top:

  • The ctoken and the nonce is only valid for the execution of one single HTTP API command
  • The ctoken is only valid within 60 seconds

Example

Plain Token: http://192.168.1.50:8080/info?token=123456
Hashed Token (Deprecated): http://192.168.1.50:8080/info?ts=20190305T01:06:53Z&rnr=4711&hash=f52eb5ce382e356c4239f8fb4d0a87402bb95b7b3124f0762b806ad7d0d01cb6
Crypted Token (NEW): http://192.168.1.50:8080/info?ctoken=a7f6b4df6758b92445bd5470b755b43ba41cf50af8b3f6e19368348ddfb1686291555dfd90b31f9333&nonce=119c38fb6d7d707b8a45f14e688b74b8c4c1acf33643c71a

Tools

Example calculation

key = SHA256 (123456) = jZae727K08KaOmKSgOaGzww/XVqGr/PKEgIMkjrcbJI= (BASE64),
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 (HEX)

nonce = nacl.randomBytes(24) = EZw4+219cHuKRfFOaIt0uMTBrPM2Q8ca (BASE64),
119c38fb6d7d707b8a45f14e688b74b8c4c1acf33643c71a (HEX)

secretbox (“2019-03-05T01:06:53Z,4711”, nonce, key) = p/a032dYuSRFvVRwt1W0O6Qc9Qr4s/bhk2g0jd+xaGKRVV39kLMfkzM= (BASE64),
a7f6b4df6758b92445bd5470b755b43ba41cf50af8b3f6e19368348ddfb1686291555dfd90b31f9333 (HEX)

Python example

import hashlib
import nacl.utils
import nacl.secret
import datetime

BRIDGE_IP  = "100.100.100.1"
BRIDGE_PORT = 8080
BRIDGE_API_TOKEN = "123456"

SESSION_KEY = hashlib.sha256(str(BRIDGE_API_TOKEN).encode('utf-8')).digest()
SESSION_NONCE = 0
SESSION_CTOKEN = 0

def init():
    print("Bridge info: "+ str(BRIDGE_IP) + ":" + str(BRIDGE_PORT) + " token=" + str(BRIDGE_API_TOKEN))

def updateNonce():
    global SESSION_NONCE
    SESSION_NONCE = nacl.utils.random(24)

def getTimestamp():
    date = datetime.date.today()
    time = datetime.datetime.utcnow().strftime("%H:%M:%S")

    timestamp = str(date) + "T" + str(time) + "Z,1234"
    print(timestamp)
    return timestamp

def updateToken():
    global SESSION_KEY
    box = nacl.secret.SecretBox(SESSION_KEY)
    timestamp = getTimestamp()

    ctoken = box.encrypt(timestamp.encode('utf-8'), SESSION_NONCE)
    global SESSION_CTOKEN
    SESSION_CTOKEN = ctoken.ciphertext.hex()

def fetchBridgeInfo():
    infoString = "http://" + str(BRIDGE_IP) + ":" + str(BRIDGE_PORT) + "/info?ctoken=" + str(SESSION_CTOKEN) + "&nonce=" + str(SESSION_NONCE.hex())
    print(infoString)

if __name__ == '__main__':
    init()
    updateNonce()
    updateToken()
    fetchBridgeInfo()

Updates

Bridge 1.0

Bridge 1.0 Beta 1.22.1

  • Initial version supporting the encrypted API token

Bridge 2.0

Bridge 2.0 Beta 2.14.0

  • Initial version supporting the encrypted API token

Could you provide a sample in nodejs? Would be awesome :wink:

1 Like