You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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="
}

核心错误点:

  1. 算法误用:ONVIF明确要求用SHA-1生成PasswordDigest,你测试时用了MD5,完全不符合规范,必须舍弃MD5的尝试。
  2. SHA-1结果处理错误:你使用的SHA-1库final()返回的是十六进制字符串,但实际上需要对SHA-1输出的20字节原始二进制数据做Base64编码,而不是对十六进制文本编码。这是导致结果错误的关键原因。
  3. 输入拼接的潜在问题:注释里的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:07:03