【Qt】Qt中QCryptographicHash , QPasswordDigestor 介绍

Qt 的 QCryptographicHash 属于【通用的加密哈希函数】,而不是【专门的密码哈希算法】。

把它归类到和 MD5、SHA256 一样的类别里是最准确的。下面进行详细解释:

1. 核心定位:通用哈希计算工具

QCryptographicHash 的设计初衷是一个工具类,用于计算任意二进制数据(比如文件、字节流)的加密哈希值,以实现:

  • 数据完整性校验:验证下载的文件是否完整、未被篡改。
  • 数字签名:作为签名算法的一部分。
  • 生成唯一标识符:根据内容生成短且唯一的密钥(例如,用于缓存文件名)。
  • 快速哈希计算:在任何需要 MD5、SHA1 等哈希值的通用场景中使用。

2. 为什么它不适合用于密码加密?

正是由于其"通用"和"工具"的属性,它具备了和 MD5 一样的、导致其不适合用于密码的所有缺陷:

  1. 纯粹且快速的哈希计算 :它只是单纯地执行所选算法(如 MD5, SHA256)的哈希计算,速度极快。这对于校验文件是优点,但对于密码存储却是致命弱点,因为攻击者可以高速进行暴力破解。
  2. 不自动加盐(Salt) :这个类不会 自动为你生成和管理盐值。如果你需要加盐,必须自己手动 生成一个随机盐,将其与密码组合,然后再调用 QCryptographicHash 进行计算。并且,你还需要自己安全地存储这个盐值(通常和哈希值存在一起)。忘记加盐或错误地加盐都会导致严重的安全问题。
  3. 不涉及成本因子(迭代次数) :像 bcrypt 这样的密码哈希算法允许你设置一个"工作因子"(或迭代次数),从而可以故意减慢计算速度,以抵御暴力破解。QCryptographicHash 没有这个功能,它的计算成本是固定的、且非常低。
  4. 不支持自适应算法:它提供的算法(MD5, SHA1, SHA256等)是固定的。而密码学的最佳实践是在发展变化的,如果未来发现 SHA256 也不安全了,你需要自己重构所有代码来更换算法。而 Qt 的密码哈希功能(后文会讲)或其它现代库会自动选择当前最安全的算法。

一个危险的示例(请不要这样做):

cpp 复制代码
// ⚠️ 警告:这是一个不安全的示例,仅用于演示问题,切勿在实际项目中使用!

QString password = "myPassword123";

QCryptographicHash hash(QCryptographicHash::Sha256);
hash.addData(password.toUtf8());

QString hashedPassword = hash.result().toHex();
// 存储 hashedPassword

这个例子的问题:

  • 没有加盐。
  • SHA256 计算速度太快。
  • 没有成本因子。

3. 在 Qt 中正确加密密码的方法

从 Qt 5.12 版本开始 ,Qt 提供了一个专门用于密码哈希的类:QPasswordDigestor。

这个类才是 Qt 世界中用于密码的正确答案,它遵循了现代密码存储的最佳实践。

推荐使用 QPasswordDigestor:
cpp 复制代码
#include <QPasswordDigestor>
#include <QRandomGenerator>

// 1. 生成一个随机的盐值(Salt)
QByteArray salt(16, '\0'); // 生成16字节的盐值
QRandomGenerator::system()->fillRange(reinterpret_cast<quint32*>(salt.data()), salt.size() / sizeof(quint32));

// 2. 定义计算参数:算法、迭代次数
// 迭代次数越高越安全,但也越慢。需要根据硬件性能权衡(通常数万到数十万次)
int iterations = 100000;
QPasswordDigestor::DerivationKey derivationKey = QPasswordDigestor::DerivationKey::Pbkdf2;

// 3. 使用 PBKDF2 算法派生密钥(即计算密码哈希)
QByteArray passwordData = "myPassword123".toUtf8();
QByteArray hashedPassword = QPasswordDigestor::deriveKeyPbkdf2(
    QCryptographicHash::Sha256, // 内部使用SHA256,但被PBKDF2包装了
    passwordData,
    salt,
    iterations, // 关键!增加了计算成本
    32 // 输出哈希值的长度(例如32字节 for SHA256)
);

// 4. 存储时,必须同时存储【哈希值】、【盐值】和【迭代次数】
// 格式可以是:`算法$迭代次数$盐$哈希` 或分开存储在数据库字段中
// 例如: "pbkdf2_sha256$100000$abcdef123456...$789abcdeff..."

关键改进:

  • 加盐:强制要求你提供随机盐。
  • 慢 :通过高迭代次数故意减慢计算速度,极大增加暴力破解成本。
  • 使用标准算法 :实现了 PBKDF2,这是一个基于标准且经过验证的密钥派生函数,常用于密码哈希。

总结对比

特性 QCryptographicHash QPasswordDigestor (推荐用于密码)
设计目的 通用数据哈希 密码哈希
速度 快(用于校验数据) 可调节的慢(用于阻止破解)
盐值 不提供,需手动实现 需要手动提供,但为必选项
成本因子 无 有(迭代次数)
适用场景 文件校验、生成唯一ID 用户密码存储

结论:
不要使用 QCryptographicHash 来直接加密密码。 它是为完全不同的任务而设计的。

对于 Qt 应用程序,如果你的版本 >= 5.12,请使用 QPasswordDigestor。如果你的 Qt 版本较老,则应使用其他专门的三方库(例如基于 OpenSSL 的实现)来正确处理密码。

相关推荐
§ꦿCFོ༉1 小时前
嵌入式八股文—C语言入门学习(四)
c语言·开发语言·学习
投图匠1 小时前
十种不同风格的 CTP接口 框架
开发语言·python
爱笑的k115 小时前
nano-vllm 源码剖析:千行 Python 手写离线推理引擎的调度、显存与并行时序
开发语言·python·vllm
X1A0RAN6 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
熊猫钓鱼>_>7 小时前
普通用户视角的端侧智能体验手记【鸿蒙心迹】
开发语言·人工智能·华为·智能手机·性能优化·ai编程·harmonyos
瑞雪兆丰年兮7 小时前
JavaWeb-day13-SpringBootWeb事务管理&AOP
java·开发语言·springboot·javaweb·事务·web·aop
布莱克6059 小时前
Swift 常量详解:从 let 到编译期优化
服务器·开发语言·ssh·swift·常量·let
布莱克6059 小时前
Swift 可选类型(Optionals)详解:从原理到实战
开发语言·安全·ssh·swift·optional·可选类型
瑞雪兆丰年兮11 小时前
JavaWeb-day14-SpringBootWeb原理篇
java·开发语言·spring boot·spring·bean·mybatis·javaweb
SomeOtherTime13 小时前
Rust生命周期介绍(AI回答)
开发语言·后端·rust