So far I have programmed login to transfer video both over the local network and over the internet. My problem now is the authenticity of the transmission of commands to the camera. With the help of ONVIF Device Manager and Wireshark, I can see how the authenticity works. The commands are sent with HTTP POST soap+xml. I have not been able to figure out how to generate "PasswordDigest" and "Base64Binery" as below.
Part if <s:Header> from ONVIF Device Manager
<UsernameToken>
<Username>
admin
</Username>
<Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
LgjVElh3j08Lk6p3HgMmypBjEVs= <!-- Changes after each command -->
</Password>
<Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
NZXdgMaDKUS7mIZNCDLydw0AAAAAAA== <!-- Changes after each session -->
</Nonce>
<Created
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
2024-03-26T06:28:59.865Z
</Created>
</UsernameToken>
My try with "PasswordDigest":
char _keys[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
void PasswordDigest() {
// Password_Digest = Base64(SHA-1(nonce + created + password))
/* Make the created */
char buffer[30];
struct timeval tv;
time_t curtime;
char created[256];
gettimeofday(&tv, NULL);
curtime = tv.tv_sec;
strftime(buffer, 30, "%Y-%m-%dT%H:%M:%S.", gmtime(&curtime));
int msec = tv.tv_usec / 1000;
sprintf(created, "%s%03dZ", buffer, msec);
// created = "2024-03-27T21:51:02.540Z"
/* Make the nonce */
uint8_t nonce[16];
srand((int)time(NULL));
for (int i = 0; i < 16; i++) {
nonce[i] = 0 + (rand() % 255); // all bytes
//int j = 0 + (rand() % sizeof(_keys));
//nonce[i] = _keys[j];
}
// nonce = "3â/ߣà@‹'o½.&"
/* Make (nonce + created + password) */
char input[512];
memset(input, 0, 512);
memcpy(input, nonce, 16);
memcpy(input + 16, created, strlen(created));
memcpy(input + 16 + strlen(created), psw, strlen(psw));
// input = "3â/ߣà@‹'o½.&.2024 - 03 - 27T21:51 : 02.540Zxxxxxxxxx"
// Test with my MD5
uint8_t hash_1[256];
memset(hash_1, 0, 256);
MD5(input, hash_1);
// hash_1 = " ¡é˜jëÆÞ¸žKg/È"
// Test with https://github.com/vog/sha1
SHA1 checksum;
checksum.update(input);
const string hash_2 = checksum.final();
// hash_2 = "500773ff22f6ca354763cc5ab6b7a1a0c3d62fae"
char* output_1 = base64Encode((char*)hash_1);
// output_1 = "NTAwNzczZmYyMmY2Y2EzNTQ3NjNjYzVhYjZiN2ExYTBjM2Q2MmZhZQ=="
char* output_2 = base64Encode((char*)hash_2.c_str());
// output_2 = "NTAwNzczZmYyMmY2Y2EzNTQ3NjNjYzVhYjZiN2ExYTBjM2Q2MmZhZQ=="
// wireshark = "LgjVElh3j08Lk6p3HgMmypBjEVs="
}
The strange thing is that hash_1 and hash_2 have different values but base64Encode generates the same value.
My try with "Base64Binary": Contrary to "PasswordDigest", I have not been able to find the prerequisites for "Base64Binary". I have tried combinations of user and password.
void Base64Binary() {
/* Make (user + password) */
char input[512];
memset(input, 0, 512);
memcpy(input, usr, strlen(usr));
memcpy(input + strlen(usr), psw, strlen(psw));
char* output = base64Encode(input);
// output = "YWRtaW5lbWJsYTM0MTE="
// wireshark = "NZXdgMaDKUS7mIZNCDLydwYAAAAAAA=="
}
Hope someone can give me a clue how to proceed. Thank you in advance.