RFC 2246 PRF function in PHP

2019-07-24 08:54发布

I've been looking all over for an implementation of the PRF function from RFC 2246. I've found three. One here, one from the openSSL library, and one from wpa_supplicant. They all return different results. So my first question is: is there sample PRF input and sample PRF output somewhere?

That function is part of connecting to a .NET web service (protected with WS-Security) from PHP.

What I've found so far is this. My client sends a request for a token first with a username/password and a nonce -- that's an RST. The server, in its RSTR, responds with another nonce and a security token. The next request from my client should come with a signature whose key is derived from the two nonces and a "master secret". That derived key is computed according to RFC 2246. And that's why I need a reliable implementation of it.

Even if I have a reliable implementation of it, what would constitute the parameters to that function in the context of WS-Security? The PRF function should take three parameters, i.e.:

secret, label, seed.

I've read here, that the label Microsoft uses is "WS-SecureConversationWS-SecureConversation", but that article was written in 2006... Now, what would be the secret? Is it the original password? The security token? A combination of those? Finally, what would be the seed? I have two nonce's -- do I concatenate them, OR them, XOR them?

I'm seriously stuck. Any help greatly appreciated.

1条回答
再贱就再见
2楼-- · 2019-07-24 09:49

I fought with this for two days, but I was ultimately successful. This is my PHP psha1 function, which is based on a C# method found at a reply to "signing SOAP message request via ADFS". Take your RST and RSTR, base64_decode each and pass them to this function as the $clientSecret and $serverSecret respectively. The token response should come with a KeySize element, which you can pass in as $sizeBits if it's not equal to 256.

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);
}
查看更多
登录 后发表回答