使用sha256 一般会导入sha.h hex.h以及files.h这几个头文件
常见的sha256使用示例
1、DigestSize 和 BlockSize()
#include "cryptlib.h"
#include "sha.h"
#include
int main (int argc, char* argv[])
{
using namespace CryptoPP;
SHA256 hash;
std::cout << "Name: " << hash.AlgorithmName() << std::endl;
std::cout << "Digest size: " << hash.DigestSize() << std::endl;
std::cout << "Block size: " << hash.BlockSize() << std::endl;
return 0;
}
结果
$ ./test.exe
Name: SHA-256
Digest size: 32
Block size: 64
2、Update()添加数据, Final()更新结果
using namespace CryptoPP;
HexEncoder encoder(new FileSink(std::cout));
std::string msg = "Yoda said, Do or do not. There is no try.";
std::string digest;
SHA256 hash;
hash.Update((const byte*)msg.data(), msg.size());
digest.resize(hash.DigestSize());
hash.Final((byte*)&digest[0]);
std::cout << "Message: " << msg << std::endl;
std::cout << "Digest: ";
StringSource(digest, true, new Redirector(encoder));
std::cout << std::endl;
运行结果
$ ./test.exe
Message: Yoda said, Do or do not. There is no try.
Digest: F00E3F70A268FBA990296B32FF2B6CE7A0757F31EC3059B13D3DB1E60D9E885C
3、 截断hash结果
std::cout << "Message: " << msg << std::endl;
hash.Update((const byte*)msg.data(), msg.size());
digest.resize(hash.DigestSize()/2);
hash.TruncatedFinal((byte*)&digest[0], digest.size());
std::cout << "Digest: ";
StringSource(digest, true, new Redirector(encoder));
std::cout << std::endl;
运行结果
$ ./test.exe
Message: Yoda said, Do or do not. There is no try.
Digest: F00E3F70A268FBA990296B32FF2B6CE7
4、 管道方式 使用HashFilter
std::string msg = "Yoda said, Do or do not. There is no try.";
std::string digest;
StringSource(msg, true, new HashFilter(hash, new StringSink(digest)));
std::cout << "Message: " << msg << std::endl;
std::cout << "Digest: ";
StringSource(digest, true, new Redirector(encoder));
std::cout << std::endl;
运行结果
$ ./test.exe
Message: Yoda said, Do or do not. There is no try.
Digest: F00E3F70A268FBA990296B32FF2B6CE7A0757F31EC3059B13D3DB1E60D9E885C
5、验证hash 结果是否符合预期
SHA256 hash;
hash.Update((const byte*)msg.data(), msg.size());
bool verified = hash.Verify((const byte*)digest.data());
if (verified == true)
std::cout << "Verified hash over message" << std::endl;
else
std::cout << "Failed to verify hash over message" << std::endl;
6、 管道的方式验证
bool result;
StringSource(digest+msg, true, new HashVerificationFilter(hash,
new ArraySink((byte*)&result, sizeof(result))));
if (result == true)
std::cout << "Verified hash over message" << std::endl;
else
std::cout << "Failed to verify hash over message" << std::endl;
7、Update() 与Final()的结合CalculateDigest()
string SHA256(string data)
{
byte const* pbData = (byte*) data.data();
unsigned int nDataLen = data.size();
byte abDigest[CryptoPP::SHA256::DIGESTSIZE];
CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen);
return string((char*)abDigest);
}
视频大文件的校验
假设某网站托管每个人都可以下载的大视频文件F。下载的浏览器需要确保文件的真实性,才能向用户展示视频内容。一种可行的方法是让网站使用抗碰撞的散列函数来散列F的内容,然后通过可信的通道将散列值分发给用户。浏览器下载文件F后,计算是否等于可信值,假如相等就将视频展示给用户。
这种方式的缺点是只有当文件下载完毕后才能开始播放文件内容。
本次实验是构建一个文件认证系统,它首先计算文件的最后一个块的哈希值,并将值附加给倒数第二个块末尾,然后计算倒数第二块的哈希值,并将结果附加到倒数第三个块末尾。以此类推,直达处理完所有的块,直到处理完所有的块。类似CBC模式。
最终将最后的哈希值通过可信通道传给用户。
当用户收到第一个块后,浏览器检查是否等于;假如相等就开始播放,同时开始下载,然后上面的方式继续下去。这时候每个块几乎就是并行的认证和播放,而不是需要完整的下载。
显然,如果哈希函数H是抗碰撞的,则攻击者如法在不被浏览器检测到的情况下,修改视频块。事实上由于,攻击者无法找在的条件下,使得
。由此可以推测第二块,第三块以及剩余的所有的块。
实验过程及编码
其实完成这个过程是分成两个块的,一部分是服务器创建的过程;一个过程就是浏览器验证的过程。本部分实验就是实现第一个过程,而第二个过程只是一个简单的分割和验证的过程。
第一个过程
1、首先我们需要读取视频文件的长度,并确认能够分多少组。
2、我们创建存储每次SHA256的hash值的空间。
3、先处理最后一个块,这个块没有前一组的链接,所以要单独处理。将散列结果链接到倒数第二块的末尾,并存储这次hash的结果。
4、将上一个块的hash结果链接到本块的末尾,再进行散列,并将结果链接到前一个块上,并存储这次hash的结果。
5、循环步骤4,直到处理完视频。
第二个过程
1、获取,并且验证是否等于
2、如果步骤1结果相等,从取出,并获取,验证是否等于。
3、重复步骤2,直到视频处理结束,或者出现校验不通过的情况出现。
编码实现
void videoAuthentication(vector& hash_result, const string& file_path)
{
HexEncoder encoder(new FileSink(std::cout));
ifstream infile;
infile.open(file_path.c_str(), ios::binary);
if (!infile.is_open())
{
cout << "open the video file error!" << endl;
exit(0);
}
//将文件指针放在末尾
infile.seekg(0, ios::end);
size_t videSize = infile.tellg();
//将文件按1KB进行切分
size_t blockNumber = videSize / 1024;
hash_result.resize(blockNumber + 1);
//先读取最后一个非整块
size_t residueSize = videSize - blockNumber * 1024;
string buffer;
buffer.clear();
buffer.resize(residueSize);
infile.seekg(videSize - residueSize);
infile.read(&buffer[0], residueSize);
//blocks.push_back(buffer);
//利用sha256处理最后一块
SHA256 hash;
string digest;
digest.resize(hash.DigestSize());
hash.Update((const byte*)buffer.data(), buffer.size());
hash.Final((byte*)&digest[0]);
hash_result[blockNumber] = digest;
buffer.resize(1024);
for (int i = (int)(blockNumber - 1); i >= 0; i--)
{
infile.seekg((size_t)(i * 1024));
infile.read(&buffer[0], 1024);
string temp =buffer + hash_result[i + 1];
hash.Update((const byte*)temp.data(), temp.size());
hash.Final((byte*)&digest[0]);
hash_result[i] = digest;
}
cout << "h0:";
StringSource(hash_result[0], true, new Redirector(encoder));
infile.close();
}
验证代码
bool result;
StringSource(digest+msg, true, new HashVerificationFilter(hash,
new ArraySink((byte*)&result, sizeof(result))));
if (result == true)
std::cout << "Verified hash over message" << std::endl;
else
std::cout << "Failed to verify hash over message" << std::endl;
03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8
5b96aece304a1422224f9a41b228416028f9ba26b0d1058f400200f06a589949
实现代码1
实现代码2
备注
之前在字符串转16进制用了很多办法,还自己实现了这个过程。哎哟喂,这是造轮子啊,好气哦。可以看实现代码1中如何实现字符串转16进制的。
参考
使用sha256处理字符串
sha2