我会事先说,我的目标是不以确保安全,而是验证数据的完整性。
我想使用OpenSSL例程为几TB的数据计算标准哈希。数据是逻辑序列化的(即一个字节数组),但分布在许多计算机上。
不是将庞大的数据集移动到单个进程(和内存空间)进行散列,而是希望传递散列“上下文”,以便散列计算可以在数据被保存的任何地方进行。
构建问题的另一种方法是,我想稍后向数据集添加字节并继续哈希计算,但会产生相同的哈希答案,就像所有字节最初都可用一样。
我遇到了一个棘手的问题,因为我无法弄清楚库如何存储“上下文”。我不知道我需要传递或保存以实现我的意图。
(可以安全地假设所有散列参与者都将使用相同版本的OpenSSL库。)
我调整了文档示例来处理两个字节块以方便讨论。现在我想知道有没有办法在chunk1和chunk2之间拔掉电脑上的插头,仍然得到相同的答案?或者如果chunk1和chunk2存储在不同的计算机上怎么办?
echo preg_replace('~^.{3}\K([^\s]*) *~', '-$1', 'jjfnj 948');
输出:
#include <openssl/evp.h>
#include <stdio.h>
#include <string.h>
void print_bytes(const unsigned char * bytes, size_t count, const char * prefix)
{
printf("%s",prefix);
for(size_t i = 0; i < count; ++i) {
printf("%02x", bytes[i]);
}
printf(" (%zd Bytes)\n", count);
}
unsigned int md5_digest_process(const EVP_MD* type, const unsigned char *input, size_t numBytes, unsigned char* hash_out) {
EVP_MD_CTX mdctx;
unsigned int hash_len = 0;
size_t chunk1_size = numBytes/2;
size_t chunk2_size = numBytes - chunk1_size;
EVP_MD_CTX_init(&mdctx);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
EVP_DigestInit_ex(&mdctx, type, NULL);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
// Hash chunk 1:
EVP_DigestUpdate(&mdctx, input, chunk1_size);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
// Hash chunk 2:
EVP_DigestUpdate(&mdctx, input+chunk1_size, chunk2_size);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
EVP_DigestFinal_ex(&mdctx, hash_out, &hash_len);
EVP_MD_CTX_cleanup(&mdctx);
return hash_len;
}
int main(int argc, char *argv[]) {
if (argc!=2) {
fprintf(stderr, "One argument string expected.\n");
return 1;
}
//OpenSSL_add_all_digests();
//const EVP_MD *md = EVP_get_digestbyname("MD5");
const EVP_MD *md = EVP_md5(); //EVP_sha256();
if(!md) {
fprintf(stderr, "Unable to init MD5 digest\n");
return 1;
}
unsigned char hash[EVP_MAX_MD_SIZE];
const unsigned char * allBytes = (const unsigned char *)argv[1];
size_t numBytes = strlen(argv[1]); // skip null terminator, consistent with command line md5 -s [string]
printf("Hashing %zd bytes. EVP_MAX_MD_SIZE is %zd, EVP_MD_CTX size is %zd bytes.\n", numBytes, EVP_MAX_MD_SIZE, sizeof(EVP_MD_CTX));
int hash_len = md5_digest_process(md, allBytes, numBytes, hash);
print_bytes(hash, hash_len, "Hash: " );
return 0;
}
由于每次更新后$ ./a.out foobar
Hashing 6 bytes. EVP_MAX_MD_SIZE is 64, EVP_MD_CTX size is 48 bytes.
EVP_MD_CTX: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
Hash: 3858f62230ac3c915f300c664312c63f (16 Bytes)
$ md5 -s foobar
MD5 ("foobar") = 3858f62230ac3c915f300c664312c63f
没有变化,我推断算法状态实际上存储在别处,我不能简单地复制48个EVP_MD_CTX字节。
我在手册中看过EVP_MD_CTX
,但我不知道如何将它用于我的目的。