1

我们正在尝试实现一个函数 P_SHA1 表示 PHP。用 Python 编写的函数模式。但是,不幸的是,有些东西不能正常工作。这是JAVA中的实现函数:http ://ws.apache.org/wss4j/xref/org/apache/ws/security/conversation/dkalgo/P_SHA1.html

我们的代码:

<?php
  $newSeed    = $label . $seed; // concat as strings
  // $p_sha1
  $psha1 = p_hash('sha1', $secret, $newSeed, $length);
  $string = arrayToBytes($psha1);
  /**
  * P_SHA1 crypto alg calculation
  *
  * @return array of bytes - key
  **/
  function p_hash($algo, $secret, $seed, $length) {
    $bytes = array_fill(0, $length, 0); 
    $tmp = null;
    $A = $seed;
    $index = 0;

    while (1) {
      // hmac sha1: secret + seed
      $A = hash_hmac($algo, $secret, $A, true);

      // hmac sha1: secret + 1st hash + seed
      $output = hash_hmac($algo, $secret, ($A . $seed), true);

      foreach (bytesToArray($output) as $c) {
          if ($index >= $length) {
              return $bytes;
          }

          $bytes[$index] = $c;
          $index++;
      }
    }
    return $bytes;
}

function bytesToArray($bytes) { return unpack('C*', $bytes); }
function arrayToBytes($array) { return call_user_func_array("pack", array_merge(array("C*"), $array)); }
?>

也许有人知道我在哪里可以找到现成的解决方案?或者任何人都可以帮助使脚本正常工作?

4

4 回答 4

3

这基于对“通过 ADFS 签署 SOAP 消息请求”的回复中包含的 C# 方法。我已经成功地使用它来签署 SOAP 请求并获得我想要的响应。

function psha1($clientSecret, $serverSecret, $sizeBits = 256)
{
    $sizeBytes = $sizeBits / 8;

    $hmacKey = $clientSecret;
    $hashSize = 160; // HMAC_SHA1 length is always 160
    $bufferSize = $hashSize / 8 + strlen($serverSecret);
    $i = 0;

    $b1 = $serverSecret;
    $b2 = "";
    $temp = null;
    $psha = array();

    while ($i < $sizeBytes) {
        $b1 = hash_hmac('SHA1', $b1, $hmacKey, true);
        $b2 = $b1 . $serverSecret;
        $temp = hash_hmac('SHA1', $b2, $hmacKey, true);

        for ($j = 0; $j < strlen($temp); $j++) {
            if ($i < $sizeBytes) {
                $psha[$i] = $temp[$j];
                $i++;
            } else {
                break;
            }
        }
    }

    return implode("", $psha);
}

需要注意的重要一点是,客户端密码和服务器密码在传递给此函数之前应该进行 base64 解码。

于 2013-11-11T16:19:29.453 回答
1

您应该提到,它是“ WS-SecureConversation 1.3 ”的实现,显然它不是 SHA1,而是具有协议细节的 HMAC-SHA1 的变体。

原来是来自TLS (RFC 2246)的东西:

我们使用 RFC 2246 中为 TLS 定义的机制的一个子集。具体来说,我们使用 P_SHA-1 函数来生成可用于生成安全密钥的字节序列。

你不是第一个问的人,例如这个问题没有答案 PHP 中的 RFC 2246 PRF 函数

于 2013-10-25T13:18:57.047 回答
0

我试着总结一下别人的答案,并给出likeuntomurphy的优秀答案的简化版。

正如Yarik 所说P_SHA1TLS 1.0 标准中定义为PRF,并被合并到WS-SecureConversation 1.3中。值得注意的是,在大约 2018 年的最新TLS 标准中,这个奇怪的功能已被一个名为HKDF的标准取代。

无论如何,这是 P_SHA-1 的简化代码:

function p_sha1(string $client_secret, string $server_secret, int $num_bytes): string
{
    $key = base64_decode($client_secret);
    $data = base64_decode($server_secret);

    $buff = $data;
    $ret = "";

    while (strlen($ret) < $num_bytes) {
        $buff = hash_hmac("SHA1", $buff, $key, TRUE);
        $ret .= hash_hmac("SHA1", $buff . $data, $key, TRUE);
    }

    return substr($ret, 0, $num_bytes);
}
于 2019-09-13T05:10:06.517 回答
-1

您是在寻找现成的SHA1函数还是其他东西?这将为您提供 SHA1 哈希,如果您在第二个参数中输入 true,它将以二进制形式提供给您。否则,它将以十六进制形式提供给您

于 2013-10-25T13:08:56.580 回答