1# BC Protocol 2 3This is an attempt to document the BC protocol. It is far from complete 4but should serve as a good basis for those wishing to develop apps for 5BC cameras. 6 7## Messages 8 9Each message has the general format: 10 11- Header: 20-24 bytes 12 13- Message Body 14 15### Header 16 17The header has the format: 18 19| magic | message id | message length | encryption offset | encrypt | message class | 20|--------------|--------------|----------------|-------------------|------------|---------------| 21| f0 de bc 0a | 01 00 00 00 | 2c 07 00 00 | 00 00 00 01 | 01 dc | 14 65 | 22 23- Magic 4 bytes 24- ID 4 bytes 25- Message length 4 bytes 26- Encryption offset 4 bytes 27- Encryption flag 1 byte 28- Unknown 1 byte 29- Message class 2 bytes 30 31Or 32 33| Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset | 34|--------------|--------------|----------------|-------------------|-------------------|---------------|----------------| 35| f0 de bc 0a | 01 00 00 00 | 28 01 00 00 | 00 00 00 01 | c8 00 | 14 64 | 00 00 00 00 | 36 37 38- Magic 4 bytes 39- ID 4 bytes 40- Message length 4 bytes 41- Encryption offset 4 bytes 42- Status Code 2 bytes 43- Message class 2 bytes 44- Binary offset 4 bytes (Presence depend on message class) 45 46#### Magic 47 48The magic bytes for BC messages is always `f0 de bc 0a` for client <-> device. 49Or magic `a0 cd ed 0f` for device <-> device, eg NVR <-> IPC. 50When receiving packet these should be used to quickly discard invalid packets. 51 52#### Message ID 53 54Each function in BC has its own message ID. For example login is 1, video data 55is 3, motion detection is 33. 56 57For a more complete list please see the [messages doc](dissector/messages.md) 58 59#### Message length 60 61The message length contains the full length of the data to follow the header 62this includes both the XML and binary parts. 63 64#### Encryption offset 65 66The encryption offset is used as part of the decoding process. It is combined 67with the key to decrypt the data. 68 69Here is an example decrypter in rust 70 71```rust 72const XML_KEY: [u8; 8] = [0x1F, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78, 0xFF]; 73 74pub fn crypt(offset: u32, buf: &[u8]) -> Vec<u8> { 75 let key_iter = XML_KEY.iter().cycle().skip(offset as usize % 8); 76 key_iter 77 .zip(buf) 78 .map(|(key, i)| *i ^ key ^ (offset as u8)) 79 .collect() 80} 81``` 82 83In short the key is offset by the encryption offset in the header. Then each 84encrypted byte is paired with the offseted keys bytes (looping the offseted 85key as necessary). Then each byte is XORed with the paired key byte and the 86offset. 87 88The key is the same for all cameras. 89 90Older cameras do not use encryption and all messages are sent as plain text. 91 92The offset bytes are actually made up of other useful information 93channel_id 1 byte - NVR channel related to request/response or `00` if N/A. 94stream_id 1 byte - `00`=clear, `01`=fluent, `04`=balanced 95unknown 1 byte - Always `00` 96message_handle 1 byte - client increments per request, replies use request handle 97 98#### Encryption Flag 99 100Client will send the number `0xXXdc` and the server will reply `0xXXdd`. 101Where `XX` is one of the following. 102 103- 0 Unencrypted 104- 1 BC Encryption 105- 2 AES Encryption (Camera) 106- 3 AES Encryption (Client) 107 108`dc` means this encryption protol or lower. So `0x01dc` means BC on no encryption 109whereas `0x03dc` means AES, BC or Unencrypted. 110 111`dd` is the reply that the camera sends to the `dc` request. It is the chosen 112protocol that will be used. 113 114**Note:** When requesting AES the client sends `0x03dc` and the camera replies `0x02dc`. 115We are not sure why. 116 117Encryption is negotiated in the login request. 118 119#### Status Code 120 121In a request this is set to `00 00`. 122In a reply this is a http style response code. 123`c8 00` = 200 OK 124`90 01` = 400 Bad Request 125 126#### Message class 127 128The message class determines the length of the header. The following classes 129and header lengths are known. 130 131- 0x6514: "legacy" 20 bytes 132 133- 0x6614: "modern" 20 bytes 134 135- 0x6414: "modern" 24 bytes 136 137- 0x0000: "modern" 24 bytes 138 139#### Payload offset 140 141For messages that contain the payload offset field this represents where to start 142the payload part of the message. The total length of the message 143(extension XML + payload) is equal to the message length in the header 144so Payload Offset is total_length - this_offset. Where as this field also represents the end of the 145extension XML part of the message. 146 147# Login 148 149For message details see the [docs](dissector/messages.md) 150 151Clients should login by 152 153- Send legacy login message 154 - User and pass MD5'ed 155 - Capped at 32 bytes with a null terminator 156 - Bytes 32 is always zero so only first 31 bytes are compared 157 158- Receive modern upgrade message with nonce in XML 159 160- Send modern login: 161 - User and pass concatenated with the nonce 162 - Send MD5'ed user and password 163 164- Receive reply with device info 165 166# Starting Video 167 168Video is requested and received with message ID 3. 169 170Video is requested with an XML of the following format: 171 172```xml 173<?xml version="1.0" encoding="UTF-8" ?> 174<body> 175<Preview version="1.1"> 176<channelId>0</channelId> 177<handle>0</handle> 178<streamType>mainStream</streamType> 179</Preview> 180</body> 181``` 182 183streamType can be either 184 185- `mainStream` in which case it will be HD 186- `subStream` in which case it will be SD 187 188 189channelId is part of the NVR when multiple cameras use the same IP. In this 190case each camera has its own channelId. 191 192The `handle` is used when multiple streams are requested in a single login. 193This number should be unique for each stream. If not then that stream 194(Clear or Fluent) will not work until the camera is reset. 195 196 197The reply is first a message with the following Extension Xml 198 199```xml 200<?xml version="1.0" encoding="UTF-8" ?> 201<Extension version="1.1"> 202<binaryData>1</binaryData> 203</Extension> 204``` 205 206After which all message bodies of type id 3 are binary. 207 208The binary represents a stream of data that can be interrupted by packet 209boundaries. Clients should create a buffer and pop bytes for processing when 210complete media packets are received. Media packets descriptions can be found in 211the [docs](dissector/mediapacket.md) 212 213# Other Function 214 215Other data can be received from the camera by sending the appropriate header to 216the camera. For example sending the header for ID 78 217 218| Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset | 219|--------------|--------------|----------------|-------------------|-------------------|---------------|----------------| 220| f0 de bc 0a | 4e 00 00 00 | d3 00 00 00 | 08 db 9c 00 | c8 00 | 00 00 | 00 00 00 00 | 221 222The camera will reply with an xml with brightness and contrast 223 224```xml 225<?xml version="1.0" encoding="UTF-8" ?> 226<body> 227<VideoInput version="1.1"> 228<channelId>0</channelId> 229<bright>128</bright> 230<contrast>128</contrast> 231<saturation>128</saturation> 232<hue>128</hue> 233</VideoInput> 234</body> 235``` 236 237Some message IDs also require input along with the request header. For example 238 239ID 151 which is the users ability info requires the header 240 241| Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset | 242|--------------|--------------|----------------|-------------------|-------------------|---------------|----------------| 243| f0 de bc 0a | 97 00 00 00 | a7 00 00 00 | 00 00 00 02 | 00 00 | 14 64 | a7 00 00 00 | 244 245and the body of 246 247```xml 248<?xml version="1.0" encoding="UTF-8" ?> 249<Extension version="1.1"> 250<userName>...</userName> <!-- Plain text username --> 251<token>system, network, alarm, record, video, image</token> 252</Extension> 253``` 254 255Which contains the plain text of the username of interest and the tokens for 256abilities you want to know about. 257 258Details of expected formats should be found from the 259[docs](dissector/messages.md) 260 261#### AES Encryption 262 263If the encryption flag returned from the camera is `0x02dd` then AES encryption will be used. 264 265The cameras use AES cfb128 with an IV of `0123456789abcdef` the key is made as follows 266 267- Concatenated the `NONCE` from login with a `-` then with your plain text password 268- MD5 Hash this concatenated string 269- Represent the hash as hex string in all caps 270- Take the first 16 characters as the encryption key 271 272 273Here is an example: 274 275```rust 276use aes::Aes128; 277use cfb_mode::cipher::{NewStreamCipher, StreamCipher}; 278use cfb_mode::Cfb; 279 280const IV: &[u8] = b"0123456789abcdef"; 281let key_phrase = format!("{}-{}", nonce, passwd); 282let key_phrase_hash = format!("{:X}\0", md5::compute(&key_phrase)) 283 .to_uppercase() 284 .into_bytes(); 285let key = key_phrase_hash[0..16]; 286 287let mut decrypted = encrypted.to_vec(); 288Cfb::<Aes128>::new(key.into(), IV.into()).decrypt(&mut decrypted); 289return decrypted; 290``` 291