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

如何在C++中生成符合ONVIF规范的Password Digest?

正确生成ONVIF密码摘要的C++实现

首先明确ONVIF密码摘要的计算规则:

PasswordDigest = Base64编码( SHA1哈希( Base64解码(Nonce) + Date + Password ) )

其中:

  • Nonce是Base64编码的随机二进制数据,不是明文字符串
  • Date必须符合ISO 8601格式(如2022-09-10T10:10:59Z,部分设备兼容带毫秒的格式,但建议用标准格式)
  • 拼接操作是字节级的直接合并,需确保字符串采用UTF-8编码

你的代码存在的问题

  • Nonce处理错误:你直接对明文"secret"做Base64解码,而实际ONVIF的Nonce是设备返回的Base64格式字符串,需先获取该值再解码
  • SHA1计算长度错误:strlen(str.c_str()) - 1会丢弃最后一个字符,正确长度应为str.size()(std::string的size()返回实际字符数,不含终止符)
  • 日期格式风险:部分ONVIF设备不支持带毫秒的日期格式,可能导致验证失败

正确的C++实现(基于OpenSSL库)

以下是使用OpenSSL工具函数的可靠实现:

#include <iostream>
#include <string>
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>

// Base64解码:将Base64字符串转为原始字节
std::string base64_decode(const std::string& input) {
    BIO *bio, *b64;
    int decode_len = 0;
    char* buffer = nullptr;

    bio = BIO_new_mem_buf(input.data(), input.size());
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_push(b64, bio);
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); // 忽略换行符

    decode_len = BIO_pending(bio);
    buffer = new char[decode_len + 1];
    decode_len = BIO_read(bio, buffer, decode_len);
    buffer[decode_len] = '\0';

    std::string result(buffer, decode_len);
    delete[] buffer;
    BIO_free_all(bio);

    return result;
}

// Base64编码:将字节数组转为Base64字符串
std::string base64_encode(const unsigned char* input, size_t length) {
    BIO *bio, *b64;
    BUF_MEM *buffer_ptr;

    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); // 不添加换行符

    BIO_write(bio, input, length);
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &buffer_ptr);

    std::string result(buffer_ptr->data, buffer_ptr->length);
    BIO_free_all(bio);

    return result;
}

// 计算ONVIF密码摘要
std::string calculate_onvif_password_digest(const std::string& nonce_b64, const std::string& date, const std::string& password) {
    // 1. 解码Base64格式的Nonce
    std::string nonce_decoded = base64_decode(nonce_b64);

    // 2. 拼接字节流:解码后的Nonce + Date字符串 + Password字符串
    std::string combined = nonce_decoded + date + password;

    // 3. 计算SHA1哈希
    unsigned char sha1_hash[SHA_DIGEST_LENGTH];
    SHA1(reinterpret_cast<const unsigned char*>(combined.data()), combined.size(), sha1_hash);

    // 4. 对哈希结果做Base64编码
    return base64_encode(sha1_hash, SHA_DIGEST_LENGTH);
}

int main() {
    // 官方示例测试(验证正确性)
    std::string nonce_b64 = "LKqI6G/AikKCQrN0zqZFlg==";
    std::string date = "2010-09-16T07:50:45Z";
    std::string password = "userpassword";

    std::string digest = calculate_onvif_password_digest(nonce_b64, date, password);
    std::cout << "官方示例摘要:" << digest << std::endl; // 应输出 tuOSpGlFlIXsozq4HFNeeGeFLEI=

    // 你的业务场景(替换为设备返回的Nonce)
    std::string your_nonce_b64 = "替换为设备返回的Base64格式Nonce";
    std::string your_date = "2022-09-10T10:10:59Z";
    std::string your_password = "mypassword";
    std::string your_digest = calculate_onvif_password_digest(your_nonce_b64, your_date, your_password);
    std::cout << "你的场景摘要:" << your_digest << std::endl;

    return 0;
}

编译与使用注意事项

  • 编译时需链接OpenSSL库,例如g++命令:g++ onvif_digest.cpp -o onvif_digest -lcrypto
  • Nonce必须使用设备在握手阶段返回的Base64值,不能自行指定明文
  • Date必须与SOAP请求中Created字段的时间完全一致,否则摘要验证会失败
  • 确保Date、Password等字符串采用UTF-8编码,避免字符编码导致的验证错误

内容的提问来源于stack exchange,提问作者O'Connor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:15:45