使用 CryptoAPI 的 C++ SHA1 和 MD5 实现





5.00/5 (22投票s)
本文介绍了一种使用 Microsoft CryptoAPI 库在 Windows 上计算哈希值(SHA1、MD5、MD4 和 MD2)的 C++ 实现。
引言
加密哈希函数广泛用于保护通信安全、在数据库中存储密码的哈希值、验证消息或文件在两个实体之间是否正确传输等。最广泛使用的算法之一是 MD5(Message Digest Five),它生成一个 128 位哈希值,通常表示为 32 个十六进制数字。它是 MD4 和 MD2 的后继者,所有这些算法都由 Ronald Rivest 开发。另一种基于 MD4 的哈希算法是 SHA-1,这是一种加密安全的单向哈希算法,可生成 160 位消息摘要(通常表示为 40 个十六进制数字)。本文介绍了一种使用 Microsoft CryptoAPI 库计算哈希值(SHA1、MD5、MD4 和 MD2)的 C++ 实现。CryptoAPI 最低要求 Windows XP 或 Windows Server 2003。
注意:MD5 和 SHA1 都已被证明存在弱点。MD5 不具备抗碰撞性,并存在其他弱点,这使其不适用于至少一些安全应用,包括 SSL 证书。US-CERT 已得出结论,MD5“应被认为在加密上已失效,不再适用于进一步使用”。SHA1 的发布者美国国家标准与技术研究院目前也在寻找 SHA1 的替代品。
一些 CryptoAPI 考虑因素
为了生成哈希值,必须遵循以下步骤:
- 初始化加密操作的上下文
- CryptAcquireContext:获取对特定加密服务提供商中密钥容器的句柄;该句柄用于后续的加密 API 调用。
- 创建哈希对象
- CryptCreateHash:为哈希数据流创建哈希对象;返回一个用于后续哈希数据或会话密钥的句柄。
- 哈希数据
- CryptHashData:将数据添加到先前创建的哈希对象中。可以多次调用以向哈希对象添加更多数据。
- 检索哈希值
- CryptGetHashValue:从哈希对象中检索数据。要检索哈希值,必须首先调用此方法并传入
HP_HASHSIZE
以确定哈希值的大小,分配哈希值内存,然后调用它并传入HP_HASHVAL
来获取哈希值。
- CryptGetHashValue:从哈希对象中检索数据。要检索哈希值,必须首先调用此方法并传入
- 通过销毁
hash
对象和释放加密上下文来清理- CryptDestroyHash:销毁先前使用
CryptCreateHash
创建的哈希对象。 - CryptReleaseContext:释放先前通过调用
CryptAcquireContext
获取的加密服务提供商和密钥容器的句柄。
- CryptDestroyHash:销毁先前使用
消息摘要实现
我的实现包含几个模板 C++ 类,它们提供:cryptohash_t
是为数据流提供哈希功能的类,而 cryptohash_helper_t
是一个辅助类,为哈希测试和文件提供简化的 API。这两个类都以哈希算法为参数。
template <ALG_ID algorithm>
class cryptohash_t;
template <ALG_ID algorithm>
class cryptohash_helper_t;
提供了几个 typedef
s 以简化这些模板类的使用。
typedef cryptohash_t<CALG_MD2> md2_t;
typedef cryptohash_t<CALG_MD4> md4_t;
typedef cryptohash_t<CALG_MD5> md5_t;
typedef cryptohash_t<CALG_SHA1> sha1_t;
typedef cryptohash_helper_t<CALG_MD2> md2_helper_t;
typedef cryptohash_helper_t<CALG_MD4> md4_helper_t;
typedef cryptohash_helper_t<CALG_MD5> md5_helper_t;
typedef cryptohash_helper_t<CALG_SHA1> sha1_helper_t;
cryptohash_t
具有以下 public
接口:
-
bool begin()
初始化哈希例程,创建用于计算数据流哈希值的哈希对象。如果函数失败,请检查最后一个错误。 -
bool update(unsigned char* const buffer, size_t size)
向当前哈希添加更多数据。如果函数失败,请检查最后一个错误。 -
bool finalize()
计算当前哈希对象的哈希值并销毁哈希对象。如果函数失败,请检查最后一个错误。 -
hash_t digest() const
以二进制格式检索计算出的哈希值。 -
std::string hexdigest(bool uppercase = false) const
以十六进制数字字符串的形式检索计算出的哈希值。 -
errorinfo_t lasterror() const
返回最后一个错误。
cryptohash_helper_t
具有以下 public
接口:
-
hash_t digesttext(std::string const& text)
计算并以二进制格式返回文本的哈希值。 -
std::string hexdigesttext(std::string const& text, bool uppercase = false)
计算并以十六进制数字字符串形式返回文本的哈希值。 -
hash_t digestfile(std::string const& filename)
计算并以二进制格式返回文件的哈希值。 -
std::string hexdigestfile(std::string const& filename, bool uppercase = false)
计算并以十六进制数字字符串形式返回文件的哈希值。 -
errorinfo_t lasterror() const
返回以上任何函数的最后一个错误。
示例
注意:在以下所有示例中,您可以直接使用任何提供的哈希类型(md5_t
、md4_t
、md2_t
、sha1_t
)或辅助类型(md5_helper_t
、md4_helper_t
、md2_helper_t
、sha1_helper_t
),而无需对示例进行任何其他更改,即可获得相应的结果。
计算字符串的 SHA-1
std::string text = "mariusbancila";
std::string digest;
sha1_t hasher;
if(hasher.begin())
{
if(hasher.update((unsigned char*)(text.c_str()), text.length()))
{
if(hasher.finalize())
{
digest = hasher.hexdigest();
}
}
}
if(digest.empty())
std::cout << "error code = " << hasher.lasterror().errorCode
<< ", error message = " << hasher.lasterror().errorMessage
<< std::endl;
else
std::cout << digest << std::endl;
计算多个字符串的 SHA-1
std::string text1 = "marius";
std::string text2 = "bancila";
std::string digest;
sha1_t hasher;
if(hasher.begin())
{
if(hasher.update((unsigned char*)(text1.c_str()), text1.length()))
{
if(hasher.update((unsigned char*)(text2.c_str()), text2.length()))
{
if(hasher.finalize())
{
digest = hasher.hexdigest();
}
}
}
}
if(digest.empty())
std::cout << "error code = " << hasher.lasterror().errorCode
<< ", error message = " << hasher.lasterror().errorMessage
<< std::endl;
else
std::cout << digest << std::endl;
使用辅助类计算字符串的 MD5
md5_helper_t hhasher;
std::string digest = hhasher.hexdigesttext("mariusbancila");
if(digest.empty())
std::cout << "error code = " << hhasher.lasterror().errorCode
<< ", error message = " << hhasher.lasterror().errorMessage
<< std::endl;
else
std::cout << digest << std::endl;
使用辅助类计算文件的 MD5
md5_helper_t hhasher;
std::string digest = hhasher.hexdigestfile("c:\\temp\\sample.png");
if(digest.empty())
std::cout << "error code = " << hhasher.lasterror().errorCode
<< ", error message = " << hhasher.lasterror().errorMessage
<< std::endl;
else
std::cout << digest << std::endl;
演示应用程序
在项目中,您可以找到一个演示应用程序(使用 Visual Studio 2008 SP1 和 MFC 编写)的源代码和二进制文件,该应用程序使用这些哈希模板类来生成文本或选定文件的哈希值(SHA1、MD5、MD4 和 MD2)。使用该应用程序非常简单,您可以在下面看到一个屏幕截图。
附加阅读材料
历史
- 2012 年 9 月 20 日:初始版本