C++开发Deltaco摄像机ONVIF管理器:认证字段生成问题
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 SHA-1 library 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=" }
核心错误点:
- 算法误用:ONVIF明确要求用SHA-1生成PasswordDigest,你测试时用了MD5,完全不符合规范,必须舍弃MD5的尝试。
- SHA-1结果处理错误:你使用的SHA-1库
final()返回的是十六进制字符串,但实际上需要对SHA-1输出的20字节原始二进制数据做Base64编码,而不是对十六进制文本编码。这是导致结果错误的关键原因。 - 输入拼接的潜在问题:注释里的
created字符串带有多余空格(2024 - 03 - 27...),实际生成的字符串必须严格是ISO 8601格式,不能有多余空格,否则哈希结果会出错。
修正步骤:
- 直接使用SHA-1算法,获取它输出的原始二进制哈希值(20字节),不要用十六进制字符串。
- 确认拼接的字节流是:16字节nonce二进制数据 + created字符串的UTF-8字节 + password字符串的UTF-8字节,无多余字符。
- 对SHA-1二进制结果执行Base64编码,得到正确的PasswordDigest。
Base64Binary(Nonce字段)生成问题
我的尝试代码:
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==" }
核心错误点:
完全误解了Nonce字段的生成逻辑!ONVIF要求的Base64Binary是对你生成的16字节随机二进制Nonce直接做Base64编码,而不是对用户名+密码的拼接字符串编码。
修正步骤:
- 保留你之前生成16字节随机二进制nonce的逻辑(这部分是对的)。
- 直接对这个16字节二进制数组执行Base64编码,得到的结果就是Nonce字段需要的Base64Binary值。
- 注意Nonce需在每次会话中更换,且Created字段的UTC时间要和Nonce生成时间严格对应,时间格式要精确到毫秒。
额外注意事项
- 确保你的Base64编码函数能正确处理任意二进制数据,有些实现会把0字节当作字符串终止符截断,导致编码错误。
- 时间生成必须用GMT时间(
gmtime),不能用本地时间(localtime),否则时区差异会导致认证失败。 - 可以用在线工具验证逻辑:比如生成16字节随机数转Base64,再把
nonce+created+password的字节流做SHA-1后转Base64,确认逻辑一致性(每次生成的结果不同,但流程正确即可)。
内容的提问来源于stack exchange,提问作者lars
相关产品推荐
相关产品推荐

