让我来回复关于sha 256和sha 512的问题。
简单来说:
算法本身不受大小端影响。大小端敏感的部分是从字节缓冲区导入数据到算法工作变量以及将其导出回摘要结果 - 这也是一个字节缓冲区。如果导入/导出包括强制转换,则大小端很重要。
强制转换可能发生在哪里:
在sha 512中,有一个128字节的工作缓冲区。
在我的代码中,它被定义为:
union
{
U64 w [80]; (see U64 example below)
byte buffer [128];
};
输入数据被复制到此字节缓冲区,然后在W上进行处理。这意味着数据已转换为某种64位类型。此数据将需要交换。在我的情况下,它被交换为小端机器。
更好的方法是准备一个获取宏,它将每个字节取出并放置在u64类型的正确位置。
当算法完成时,摘要结果从工作变量输出到某些字节缓冲区,如果使用memcpy完成,则还必须进行交换。
在32位机器上实现面向64位机器的sha 512时,可能会发生另一种转换。在我的情况下,定义了一个64位类型。
typedef struct {
uint high;
uint low;
} U64;
假设我也为小端定义了它,如下所示:
typedef struct {
uint low;
uint high;
} U64;
然后 k 算法的初始化步骤如下:
static const SHA_U64 k[80] =
{
{0xD728AE22, 0x428A2F98}, {0x23EF65CD, 0x71374491}, ...
...
...
}
但是我需要k [0] .high的逻辑值在任何机器上都相同。因此,在这个例子中,我将需要另一个具有高位和低位值交换的k数组。
在数据存储在工作参数中之后,任何位操作都会在大/小端机器上产生相同的结果。
一个好的方法是避免任何强制转换:使用宏从输入缓冲区导入字节到您的工作参数。使用逻辑值处理而不考虑内存映射。使用宏将输出导出到摘要结果。
从字节缓冲区取32位到int32的宏(BE = big endian):
#define GET_BE_BYTES_FROM32(a)
((((NQ_UINT32) (a)[0]) << 24) |
(((NQ_UINT32) (a)[1]) << 16) |
(((NQ_UINT32) (a)[2]) << 8) |
((NQ_UINT32) (a)[3]))
#define GET_LE_BYTES_FROM32(a)
((((NQ_UINT32) (a)[3]) << 24) |
(((NQ_UINT32) (a)[2]) << 16) |
(((NQ_UINT32) (a)[1]) << 8) |
((NQ_UINT32) (a)[0]))
struct
,一次是小端,一次是大端,并且您对它们进行哈希处理,它们当然会产生不同的哈希值。但这是因为它们是不同的二进制数据,而不是哈希关心的原因。 - Damon