Baichuan "modern" login: nonce, hashed credentials and the session key.
The login takes two round trips, both XOR-encrypted:
cmd 1, class 0x1465, no body -> <Encryption><nonce>...</nonce></Encryption> cmd 1, class 0x1464, loginXml -> status 200, or 401 on bad credentials
Everything after that is AES-encrypted with the key from loginCredentials.
Build the login body from a nonce
Build the login body from a nonce
import { assertEquals, assertStringIncludes } from "@std/assert"; import { loginCredentials, loginXml, parseNonce, } from "@hertzg/reolink-api/protocol/login"; const nonce = parseNonce( "<body><Encryption><nonce>NONCE-0123</nonce></Encryption></body>", ); const credentials = loginCredentials({ username: "admin", password: "hunter2", nonce, }); assertEquals(nonce, "NONCE-0123"); assertStringIncludes( loginXml(credentials), "<userName>329F51D2942C5953794C5C99EB43D46</userName>", );
Derives the hashed credentials and the AES session key from a nonce.
Builds the XML body of the login request.
Hashes a string the way Baichuan's modern login does: MD5 of the UTF-8 bytes, as upper-case hex, with the last hex digit dropped (31 characters).
Reads the nonce from the camera's reply to the nonce request.
The hashed credentials sent at login, and the session key that follows.
-
aesKey: Uint8Array
The first 16 characters of
md5Modern(nonce + "-" + password), as UTF-8 bytes. -
passwordHash: string
md5Modern(password + nonce). -
userHash: string
md5Modern(username + nonce).
What the login needs: the user's credentials and the camera's nonce.
-
nonce: string
The nonce from the camera's encryption reply, see parseNonce.
-
password: string
The camera password.
-
username: string
The camera user name.
Usage
import * as mod from "protocol/login.ts";