Little Endian数据和sha 256

问题描述:

我必须生成sha256哈希值的小数字形式的数据。我想知道在使用sha 256算法之前,是否必须先将它转换为大端。或者,如果算法是“endian-agnostic”。Little Endian数据和sha 256

编辑:对不起,我想我没有清楚。我想知道的是以下几点:sha256算法需要填充消息的结尾以确定位。第一步是在消息的末尾添加1。然后,用零填充它直到最后。最后,您必须以位为单位添加消息的长度。我想知道的是,如果这个填充可以在小端进行。例如,对于一个640位的消息,我可以将最后一个单词写为0x280(大端)或0x8002000(小端)。这个填充可以在小端进行吗?

+1

这是棘手...虽然在一般情况下,SHA不关心字节序。对于散列,任何输入都是二进制“blob”的512位块的倍数(如果有必要,它将添加填充)。就此而言,排序是微不足道的。另一方面,如果你有一个'struct'一次,一次大的endian,并且你散列它们,它们当然会产生不同的散列。但那是因为它们是不同的二进制数据,并不是因为哈希值得关注。 – Damon 2011-06-07 18:16:46

+0

@Damon:是的好点。 – Heisenbug 2011-06-07 18:18:36

+0

请参阅我的编辑 – 2011-06-07 19:23:55

SHA-256实现本身应该注意填充 - 除非要实现自己的专用SHA-256代码,否则不应该处理这种填充。如果是,请注意在“预处理步骤”中指定的填充规则说明该长度是一个64位的大端整数。请参阅SHA-2 - Wikipedia

很难弄清楚“endian-agnostic”意味着什么,但散列算法的所有位,字节和单词的顺序很重要,所以我肯定不会使用该术语。

如果你想要的只是一个很好的散列,SHA256是endian不可知的。但是,如果您正在编写SHA256并希望通过正确的实现获得相同的结果,那么您必须在小端硬件上玩游戏。 SHA256结合了算术加法(mod 2 * 32)和布尔操作,因此在内部不是不可知的。

让我回答关于sha 256以及sha 512. 简而言之: 算法本身是endian不可知的。 endian敏感部分是当数据从字节缓冲区导入到算法工作变量以及导出到摘要结果时 - 也是字节缓冲区。如果导入/导出包括转换,则endian很重要。

哪里可能发生铸造: 在sha 512有一个128字节的工作缓冲区。 在我的代码其定义的是这样的:

union 
    { 
     U64 w [80]; (see U64 example below) 
     byte buffer [128]; 
    }; 

输入数据被复制到该字节的缓冲区,然后工作是在做W.这意味着数据流延到一些64位的类型。这些数据将不得不交换。在我的情况下,它换成小端机器。

更好的方法是准备一个获取每个字节并将其放置在u64类型的正确位置的get宏。

算法完成后,摘要结果会从工作变量输出到某个字节缓冲区,如果这是通过memcpy完成的,它也必须交换。

在32位机器上执行sha 512(专为64位机器设计)时,可能会发生另一种情况。在我的情况我有一个定义的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 =大端):

#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]))