【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 的实现)来正确处理密码。

相关推荐
枫の准大一1 小时前
【C++游记】物种多样——谓之多态
开发语言·c++
JuneXcy3 小时前
循环高级(1)
c语言·开发语言·算法
MediaTea4 小时前
Python 第三方库:lxml(高性能 XML/HTML 解析与处理)
xml·开发语言·前端·python·html
编啊编程啊程4 小时前
响应式编程框架Reactor【3】
java·开发语言
Ka1Yan4 小时前
什么是策略模式?策略模式能带来什么?——策略模式深度解析:从概念本质到Java实战的全维度指南
java·开发语言·数据结构·算法·面试·bash·策略模式
胡萝卜的兔5 小时前
go 使用rabbitMQ
开发语言·golang·rabbitmq
你我约定有三5 小时前
面试tips--java--equals() & hashCode()
java·开发语言·jvm
努力也学不会java6 小时前
【设计模式】简单工厂模式
java·开发语言·设计模式·简单工厂模式
奥特曼狂扁小怪兽7 小时前
Qt图片上传系统的设计与实现:从客户端到服务器的完整方案
服务器·开发语言·qt
奥特曼狂扁小怪兽8 小时前
Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)
开发语言·qt·编辑器