在perl中实现sha-256

时间:2012-05-31 09:26:44

标签: 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

2 个答案:

答案 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方式编号,如0x010x020x040x080x10,{{1 },0x200x40。例如,将单个输入字节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

符合规范。