【问题标题】:How to compute hash for structure如何计算结构的哈希
【发布时间】:2020-04-28 08:46:45
【问题描述】:

我正在寻找如何计算数据结构哈希的解决方案。假设我们有这样的结构:

struct A
{
    float64_t array[4][4];
    float64_t x;
    float64_t y;
    uint8_t validationHash[32]; // here computed hash need to be stored
}

我还有函数Sha256(cont char * input, uint8_t (&output)[32]),它作为参数接受输入和输出——计算哈希。我知道我需要将每个值从结构转换为 const char *。但是我的问题是接下来要做什么,我应该为数组 x 和 y 中的每个值计算一个单独的哈希并将它们加在一起还是什么?

Sha256 的实现与这里http://www.zedwood.com/article/cpp-sha256-function 相同

【问题讨论】:

  • 如果你想计算一个结构的散列,那么散列应该在那个结构中。
  • 您可能无法使用 Sha256 执行此操作。此函数可能是为作为 NUL 终止字符串的输入而设计的。您需要告诉我们更多关于该功能的信息。
  • 如何告诉Sha256函数输入数组有多少字节?
  • 你想让哈希做什么?您想防止意外或恶意修改吗?
  • @MateuszCzerepowicki 如果您需要验证收到的哈希但不知道收到的哈希是如何计算的,那么您就不走运了。没有通用的、不可侵犯的计算哈希值的方法,也没有在哈希过程中组合多个值的方法。询问向您发送哈希的实体如何计算它。

标签: c++ hash sha256 sha


【解决方案1】:

您链接到的 SHA-256 哈希函数与大多数加密哈希实现一样,接受一个字节数组作为其输入。所以第一步是序列化你想要散列的数据。

这并不像将结构转换为字节数组那么简单。序列化应该在操作系统和硬件之间是可移植的。结构对齐、字节顺序等可能因系统而异,因此最好使用序列化库,并将所有这些棘手的严格别名问题留给库作者。

最佳选择:序列化库

由于您似乎已经在使用 Boost(float64_t 类型),您可以使用 Boost 序列化库。首先,创建一个序列化函数来指示Boost如何序列化A

namespace boost {
namespace serialization {

template<class Archive>
void serialize(Archive & ar, A & a, const unsigned int version)
{
    ar & a.array;
    ar & a.x;
    ar & a.y;
}

} // namespace serialization
} // namespace boost

然后,将其序列化为内存流:

std::ostringstream plaintext_buffer {};
{
    boost::archive::binary_oarchive oa(plaintext_buffer);
    oa << a;
}
std::string plaintext = plaintext_buffer.str();

现在您可以使用 SHA-256 哈希函数了。我会把这部分作为练习留给你。

  • 输入:plaintext.data() 用于数据,plaintext.size() 用于大小
  • 输出:a.validationHash

好选项:自定义浮点序列化器

根据 cmets,您仅限于 C++03(我将其视为 C++98),并且不能使用任何库。因此,首先,让我们使用最接近的等效标准类型重新定义您的函数:

struct A
{
    double array[4][4];
    double x;
    double y;
    uint8_t validationHash[32]; // here computed hash need to be stored
}

我稍微修改了这个答案:Serialize double and float with C,它声称是便携式 IEEE 754 串行器。凉爽的!我将输出更改为内存缓冲区,替换了 goto,并将 C 类型转换转换为 static_cast

void serializeIeee754(double x, uint8_t* destination)
{
    int                     shift;
    unsigned long           sign, exp, hibits, hilong, lowlong;
    double                  fnorm, significand;
    int                     expbits = 11;
    int                     significandbits = 52;

    if(x == 0) {
        /* zero (can't handle signed zero) */
        hilong = 0;
        lowlong = 0;
    } else if(x > DBL_MAX) {
        /* infinity */
        hilong = 1024 + ((1 << (expbits - 1)) - 1);
        hilong <<= (31 - expbits);
        lowlong = 0;
    } else if(x < -DBL_MAX) {
        /* -infinity */
        hilong = 1024 + ((1 << (expbits - 1)) - 1);
        hilong <<= (31 - expbits);
        hilong |= (1 << 31);
        lowlong = 0;
    } else if(x != x) {
        /* NaN - dodgy because many compilers optimise out this test
        * isnan() is C99, POSIX.1 only, use it if you will.
        */
        hilong = 1024 + ((1 << (expbits - 1)) - 1);
        hilong <<= (31 - expbits);
        lowlong = 1234;
    } else {
        /* get the sign */
        if(x < 0) {
            sign = 1;
            fnorm = -x;
        } else {
            sign = 0;
            fnorm = x;
        }

        /* get the normalized form of f and track the exponent */
        shift = 0;
        while(fnorm >= 2.0) {
            fnorm /= 2.0;
            shift++;
        }
        while(fnorm < 1.0) {
            fnorm *= 2.0;
            shift--;
        }

        /* check for denormalized numbers */
        if(shift < -1022) {
            while(shift < -1022) {
                fnorm /= 2.0;
                shift++;
            }
            shift = -1023;
        } else {
            /* take the significant bit off mantissa */
            fnorm = fnorm - 1.0;
        }
        /* calculate the integer form of the significand */
        /* hold it in a  double for now */

        significand = fnorm * ((1LL << significandbits) + 0.5f);

        /* get the biased exponent */
        exp = shift + ((1 << (expbits - 1)) - 1);   /* shift + bias */

        /* put the data into two longs */
        hibits = static_cast<long>(significand / 4294967296);  /* 0x100000000 */
        hilong = (sign << 31) | (exp << (31 - expbits)) | hibits;
        lowlong = static_cast<unsigned long>(significand - hibits * 4294967296);
    }

    destination[0] = lowlong & 0xFF;
    destination[1] = (lowlong >> 8) & 0xFF;
    destination[2] = (lowlong >> 16) & 0xFF;
    destination[3] = (lowlong >> 24) & 0xFF;
    destination[4] = hilong & 0xFF;
    destination[5] = (hilong >> 8) & 0xFF;
    destination[6] = (hilong >> 16) & 0xFF;
    destination[7] = (hilong >> 24) & 0xFF;
}

现在,您可以为A 编写自己的序列化程序,写入一个 144 字节的缓冲区:

void serializeA(A& a, uint8_t destination[144]) {
    uint8_t* out = destination;
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            serializeIeee754(a.array[i][j], out);
            out += 8;
        }
    }
    serializeIeee754(a.x, out);
    out += 8;
    serializeIeee754(a.y, out);
}

然后将该缓冲区提供给您的哈希函数。

【讨论】:

  • 问题是我不能在我的项目中使用boost库。
  • 可以使用什么?任何第三方库?
  • 不,我只能使用 c++03 并遵守 misra 规则
猜你喜欢
  • 2019-10-03
  • 2010-12-07
  • 2011-07-22
  • 2016-11-23
  • 2016-06-23
  • 2019-05-31
  • 1970-01-01
相关资源
最近更新 更多