C:SHA-1的输出为小端到浮点数

时间:2017-12-10 15:48:59

标签: c endianness sha

根据this documentation,我的任务是根据字母数字识别器计算颜色值。我们的想法是通过SHA-1运行标识符字符串,并使用结果的一部分来计算颜色值。

我在执行以下步骤时遇到了问题:

  

将输出视为小端,并提取最后有效的16位。 (这是输出的前两个字节,第二个字节是最重要的字节。)

这是我到目前为止所拥有的:

double get_CbCr_angle(const char* identifier) {

    unsigned char temp[SHA_DIGEST_LENGTH];
    char buf[SHA_DIGEST_LENGTH*2];

    // initalise with 0s
    memset(buf, 0x0, SHA_DIGEST_LENGTH*2);
    memset(temp, 0x0, SHA_DIGEST_LENGTH);

    // compute hash into temp
    SHA1((unsigned char *)identifier, strlen(identifier), temp);

    // print from temp into buf and
    // interpret as (signed) chars
    int i = 0;
    for (i=0; i < SHA_DIGEST_LENGTH; i++) {
        sprintf( (char*) &(buf[i*2]), "%02x", temp[i]);
    }

    printf("SHA1 is %s\n", buf);

    // make a union type of char and float so we can read a char array
    // as float.
    union charFloat {
        float f;
        char s[sizeof(float)];
    };

    union charFloat foo;

    // put first two chars (bytes) into union.
    // bracket notation should be fine since both foo and buf are
    // char arrays.
    foo.s[0] = buf[1];
    foo.s[1] = buf[0];

    printf("interpreted as chars: %s\n", foo.s);
    printf("interpreted as float: %f\n", foo.f);  // 0.000000 - why?

}

但是这种方法无法获得任何合理的输出。使用更多字节只会为float提供无意义的值,以及将其解释为int

显然我不希望有人为我解决这个问题。我非常感谢一些方向的提示。

提前多多感谢。

2 个答案:

答案 0 :(得分:4)

让我们仔细看看这个算法:

  
      
  1. 通过SHA-1(RFC 3174 [4])运行输入。
  2.   
  3. 将输出视为小端,并提取最后有效的16位。 (这是输出的前两个字节,第二个   字节是最重要的一个。)
  4.   
  5. 将值除以65536(使用浮点除法)并乘以2π(两个Pi)。
  6.   

该算法并未将前两个字节视为浮点值。它表示将它们视为16位整数,然后将该值转换为浮点类型以用于下一步。

此外,转换值时,您应该使用temp而不是buf,因为buf包含代表哈希输出的可打印字符,而temp包含实际输出。 / p>

所以你要转换这样的值:

uint16_t value;
value = temp[0];
value |= temp[1] << 8;

然后将其投射到double以进行下一步:

double result = value * 2 * M_PI / 65536;

答案 1 :(得分:3)

我会通过使用显式移位和OR从两个uint16_t组合char来实现此目的:

uint16_t x = (((uint16_t)(uint8_t)temp[1]) << 8) |
             (((uint18_t)(uint8_t)temp[0]) << 0);

双重演员必须确保每个char值为零,而不是在班次之前符号扩展到uint16_t的宽度。另请注意,我正在阅读temp,而不是buf - 原始 SHA哈希,而不是十六进制编码哈希。使用十六进制编码的哈希将限制x可能采用的值。

然后,将x转换为[0, 1)范围内的浮点数除以65536:

double f = x / 65536.0;

65536是2 16 ; uint16_t的值范围是0到65535,包括0和65535。除数上的.0后缀是使C执行浮点而不是整数除法所必需的。为了提高效率,这种划分可以与下一步乘以2π结合起来:

double f = x * (2 * M_PI / 65536);

M_PI(在math.h中声明)已经是一个浮点数,所以我们不再需要65536上的.0后缀,但是你需要在整个子表达式周围加上括号2 * M_PI / 65536强制编译器在编译时评估该部分,并仅发出一次运行时乘法。