在perl中实现sha-256

nap*_*cae 6 perl padding sha

我正在努力实现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

mor*_*itz 5

首先,我希望你这样做只是一个练习 - Digest核心中有一个模块已经很好地计算了SHA-256.

注意,$message .= (chr 0x80);附加一个字节,而不是一个位.如果您确实需要按位操作,请查看该vec函数.

要获得整数的二进制表示,您应该使用pack.要使它达到64位,做类似的事情

$message .= pack 'Q', length($message)
Run Code Online (Sandbox Code Playgroud)

请注意,'Q'格式仅适用于64位perls; 如果你的不是一个,只需将四个0字节与32位值(包格式L)连接起来.


Gre*_*con 5

如果可能的话,从架子上拿一些东西。您不想推出自己的 SHA-256 实现,因为要获得官方支持,您必须对其进行认证。

也就是说,规范是

5.1.1 SHA-1、SHA-224 和 SHA-256

假设消息的长度Ml位。将该位附加1到消息的末尾,后跟k 个零位,其中k是方程的最小非负解

l + 1 + k ≡ 448 mod 512

然后附加等于使用二进制表示表示的数字l的 64 位块。例如,(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
Run Code Online (Sandbox Code Playgroud)

然后填充消息的长度现在应该是 512 位的倍数。

您可能很想使用vec它,因为它允许您寻址单个位,但您必须解决时髦的寻址问题。

如果位为 4 或更少,则将字符串拆分为字节,然后将每个字节的位拆分为 8/ BITS组。字节的位以小端方式编号,如0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80。例如,将单个输入字节chr(0x36)分成两组给出一个列表(0x6, 0x3);将其分成 4 组给出(0x2, 0x1, 0x3, 0x0).

相反,指定的pack模板B*

一个位串(每个字节内的降序位顺序)。

N

“网络”(大端)顺序的无符号长整型(32 位)。

后者对于组装消息长度很有用。虽然packQquad的参数,但结果是按本机顺序排列的。

从一些准备工作开始

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;
}
Run Code Online (Sandbox Code Playgroud)

那么你可以定义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;
}
Run Code Online (Sandbox Code Playgroud)

说代码打印填充的消息

my $padded = pad_message "abc";

# break into multiple lines for readability
for (unpack("H*", $padded) =~ /(.{64})/g) {
  print $_, "\n";
}
Run Code Online (Sandbox Code Playgroud)

然后输出是

61626380000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000018

符合规范。