为什么没有转换为 Big Endian 的 Arduino(Little Endian)上的 Sha1 工作?

Why does Sha1 on Arduino (Little Endian) without conversion to Big Endian work?

我很幸运地说,我的简单 SHA1 哈希生成器代码似乎运行良好。不幸的是,我知道这个 Arduino 程序以 Little Endianness 运行,并且关于生成哈希的方法的描述要求将原始消息长度附加为 Big Endian 整数。

  1. 这意味着对于消息 char m[] = "Applecake" 我将有 9*8 位,表示为 64 位无符号整数,即 0x0000 0000 0000 0048。这意味着,使用 Little Endian 存储,内存将如下所示:0x0048 0000 0000 0000.

  2. Section 4 of RFC 3174 步骤 c) 中所述,我必须

    Obtain the 2-word representation of l, the number of bits in the original message. If l < 2^32 then the first word is all zeroes. Append these two words to the padded message.

    所以根据我上面描述的内存,我必须先将它转换为 Big Endian,然后将低 32 位附加到填充的消息中。

问题是,如果我确实转换了长度的字节顺序,我知道它是 Little Endian,我得到了错误的填充,因此得到了错误的散列。

为什么我的代码在没有转换 Endianness 的情况下工作?
我的代码在不同 Arduino、微控制器和编译器之间的兼容性方面有哪些限制?


// initialize variables
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;

// calculate the number of required cycles and create a blocks array
uint32_t numCycles = ((ml+65)/512)+1;
uint32_t blocks[numCycles*16] = {};

// copy message
uint32_t messageBytes = ml/8 + (ml%8!=0 ? 1 : 0);
for (uint32_t i = 0; i < messageBytes; i++) {
    blocks[i/4] |= ((uint32_t) message[i]) << (8*(3-(i%4)));
}

// append the 1 bit
blocks[ml/32] |= ((uint32_t) 0b1) << (31-(ml%32));

// append the 64-bit big endian ml at the end
if (ml < 0x80000000)
    blocks[(numCycles*16)-1] = (uint32_t) ml;
else {
    blocks[(numCycles*16)-2] = (uint32_t) ml;
    blocks[(numCycles*16)-1] = (uint32_t) (ml >> 32);
}

for (uint32_t iCycle = 0; iCycle < numCycles; iCycle++) {
    // initalize locals
    uint32_t w[80] = {};
    uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
    
    for (uint8_t i = 0; i < 80; i++) {
        // convert words to big-endian and copy to 80-elem array
        if (i < 16)
            w[i] = blocks[(iCycle*16)+i];
        else
            w[i] = rotL((w[i-3]^w[i-8]^w[i-14]^w[i-16]), 1);
        
        // run defined formulas
        uint32_t f, k, temp;
        if (i < 20) {
            f = (b & c) | ((~b) & d);
            k = 0x5A827999;
        }
        else if (i < 40) {
            f = b ^ c ^ d;
            k = 0x6ED9EBA1;
        }
        else if (i < 60) {
            f = (b & c) | (b & d) | (c & d);
            k = 0x8F1BBCDC;
        }
        else {
            f = b ^ c ^ d;
            k = 0xCA62C1D6;
        }
        temp = rotL(a, 5) + f + e + k + w[i];
        e = d; d = c; c = rotL(b, 30); b = a; a = temp;
    }
    
    // write back the results
    h0 += a; h1 += b; h2 += c; h3 += d; h4 += e;
}
// append the 64-bit big endian ml at the end
if (ml < 0x80000000)
    blocks[(numCycles*16)-1] = (uint32_t) ml;
else {
    blocks[(numCycles*16)-2] = (uint32_t) ml;
    blocks[(numCycles*16)-1] = (uint32_t) (ml >> 32);
}

这会将 most-significant 32 位值放在第一位,然后将 least-significant 32 位值放在第二位。这是您的代码工作的一半原因。

另一半是,虽然 32 位值采用 little-endian 形式,但您正在 little-endian 平台上读取它们的 。这将始终为您提供正确的价值。您永远不会尝试访问 32 位值的各个字节,因此哪些字节去哪里没有区别。