如果可能的话,把一些东西从架子上拿下来。您不想推出自己的 SHA-256 实现,因为要获得官方的祝福,您必须对其进行认证。
也就是说,规范是
5.1.1 SHA-1、SHA-224 和 SHA-256
假设消息的长度M为l位。将该位附加1
到消息的末尾,后跟k个零位,其中k是方程的最小非负解
l + 1 + k ≡ 448 mod 512
然后附加等于使用二进制表示表示的数字l的 64 位块。例如,(8 位 ASCII)消息“<strong>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
, 0x20
, 0x40
, 0x80
。例如,将单个输入字节chr(0x36)
分成两组给出一个列表(0x6, 0x3)
;把它分成 4 组给出(0x2, 0x1, 0x3, 0x0)
。
相反,pack
模板B*
指定
一个位串(每个字节内的降序位顺序)。
和N
“网络”(大端)顺序的无符号长整数(32 位)。
后者对于组装消息长度很有用。虽然pack
有Q
quad的参数,但结果是本机顺序。
从一些准备工作开始
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;
}
假设代码打印填充消息
my $padded = pad_message "abc";
# break into multiple lines for readability
for (unpack("H*", $padded) =~ /(.{64})/g) {
print $_, "\n";
}
然后输出是
616263800000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000018
符合规范。