SHA256用法示例 以及使用SHA256進行視頻文件校驗


使用sha256 一般會導入sha.h hex.h以及files.h這幾個頭文件

常見的sha256使用示例

1、DigestSize 和 BlockSize()

#include "cryptlib.h"
#include "sha.h"
#include <iostream>

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<string>& 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;

實驗結果
1、test.mp4結果

03c08f4ee0b576fe319338139c045c89c3e8e9409633bea29442e21425006ea8

2、video.mp4結果

5b96aece304a1422224f9a41b228416028f9ba26b0d1058f400200f06a589949

實現代碼1
實現代碼2

備注

之前在字符串轉16進制用了很多辦法,還自己實現了這個過程。哎喲喂,這是造輪子啊,好氣哦。可以看實現代碼1中如何實現字符串轉16進制的。

參考

使用sha256處理字符串
sha2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM