我正在努力实现sha-256算法。我有填充消息的问题。对于sha-256,你必须在消息的末尾追加一位,到目前为止我已经使用$message .= (chr 0x80);
下一步应该是用0填充emtpy空间(512位块)。
我用这个公式计算它:l + 1 + k = 448-l然后将它追加到消息中。
我的问题现在出现了:在最后的64位块中追加消息长度的二进制表示,并用0再次填充其余部分。由于perl自己处理数据类型,因此没有“byte”数据类型。我怎样才能知道应该添加哪个值?
请参阅官方规格: http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
答案 0 :(得分:5)
首先,我希望你这样做只是一个练习 - 核心中有一个Digest
模块已经很好地计算了SHA-256。
请注意$message .= (chr 0x80);
附加一个字节,而不是一位。如果您确实需要按位操作,请查看vec
函数。
要获取整数的二进制表示,您应该使用pack。要使其达到64位,请执行类似
的操作$message .= pack 'Q', length($message)
请注意,'Q'格式仅适用于64位perls;如果你的不是一个,只需将四个0字节与32位值(包格式L
)连接起来。
答案 1 :(得分:4)
如果可能的话,从架子上拉出一些东西。你不想推出自己的SHA-256实现,因为要得到官方的祝福,你必须得到它的认证。
那说,规范是
5.1.1 SHA-1,SHA-224和SHA-256
假设消息的长度 M 是 l 位。将位
1
附加到消息的末尾,然后是 k 零位,其中 k 是等式的最小的非负解决方案l + 1 + k ≡448mod 512
然后附加64位块,该块等于使用二进制表示形式表示的数字 l 。例如,(8位ASCII)消息“ abc ”的长度为8×3 = 24,因此消息用一位填充,然后448 - (24 + 1)= 423零位,然后是消息长度,成为512位填充消息
423 64 .-^-. .---^---. 01100001 01100010 01100011 1 00…00 00…011000 “a” “b” “c” '-v-' l=24
然后填充消息的长度现在应该是512位的倍数。
您可能很想使用vec
,因为它允许您处理单个位,但您必须解决时髦的寻址问题。
如果位为4或更小,则字符串被分成字节,然后每个字节的位被分成8 / BITS 组。一个字节的位用little-endian-ish方式编号,如
0x01
,0x02
,0x04
,0x08
,0x10
,{{1 },0x20
,0x40
。例如,将单个输入字节0x80
分成两组,得到一个列表chr(0x36)
;将其分成4组给出(0x6, 0x3)
。
相反,(0x2, 0x1, 0x3, 0x0)
的{{1}}模板指定了
一个位串(每个字节内的位顺序递减)。
和B*
“网络”(big-endian)顺序中的无符号长(32位)。
后者对于组合消息长度很有用。虽然N
对于quad有pack
参数,但结果是本机顺序。
从准备工作开始
Q
然后您可以将our($UPPER32BITS,$LOWER32BITS);
BEGIN {
use Config;
die "$0: $^X not configured for 64-bit ints"
unless $Config{use64bitint};
# create non-portable 64-bit masks as constants
no warnings "portable";
*UPPER32BITS = \0xffff_ffff_0000_0000;
*LOWER32BITS = \0x0000_0000_ffff_ffff;
}
定义为
pad_message
假设代码用
打印填充的消息sub pad_message {
use bytes;
my($msg) = @_;
my $l = bytes::length($msg) * 8;
my $extra = $l % 512; # pad to 512-bit boundary
my $k = 448 - ($extra + 1);
# append 1 bit followed by $k zero bits
$msg .= pack "B*", 1 . 0 x $k;
# add big-endian length
$msg .= pack "NN", (($l & $UPPER32BITS) >> 32), ($l & $LOWER32BITS);
die "$0: bad length: ", bytes::length $msg
if (bytes::length($msg) * 8) % 512;
$msg;
}
然后输出
6162638000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000018
符合规范。