<?php
/**
 * Created by JetBrains PhpStorm.
 * User: max
 * Date: 29-1-14
 * Time: 11:55
 * To change this template use File | Settings | File Templates.
 */
require_once 'rc4.php';
require_once 'func.php';

class KeyStream
{
    public static $AuthMethod = 'WAUTH-2';
    const DROP = 768;
    private $rc4;
    private $seq = 0;
    private $macKey;
    //key = password, mackey = challengedata

    public function __construct($key, $macKey)
    {
        $this->rc4 = new rc4($key, self::DROP);
        $this->macKey = $macKey;
    }

    public static function GenerateKeys($password, $nonce)
    {
        $array = [
            'key', //placeholders
            'key',
            'key',
            'key',
        ];
        $array2 = [1, 2, 3, 4];
        $nonce .= '0';
        for ($j = 0; $j < count($array); $j++) {
            $nonce[(strlen($nonce) - 1)] = chr($array2[$j]);
            $foo = wa_pbkdf2('sha1', $password, $nonce, 2, 20, true);
            $array[$j] = $foo;
        }

        return $array;
    }

    public function DecodeMessage($buffer, $macOffset, $offset, $length)
    {
        $mac = $this->computeMac($buffer, $offset, $length);
        //validate mac
        for ($i = 0; $i < 4; $i++) {
            $foo = ord($buffer[$macOffset + $i]);
            $bar = ord($mac[$i]);
            if ($foo !== $bar) {
                throw new Exception("MAC mismatch: $foo != $bar");
            }
        }

        return $this->rc4->cipher($buffer, $offset, $length);
    }

    public function EncodeMessage($buffer, $macOffset, $offset, $length)
    {
        $data = $this->rc4->cipher($buffer, $offset, $length);
        $mac = $this->computeMac($data, $offset, $length);

        return substr($data, 0, $macOffset).substr($mac, 0, 4).substr($data, $macOffset + 4);
    }

    private function computeMac($buffer, $offset, $length)
    {
        $hmac = hash_init('sha1', HASH_HMAC, $this->macKey);
        hash_update($hmac, substr($buffer, $offset, $length));
        $array = chr($this->seq >> 24)
            .chr($this->seq >> 16)
            .chr($this->seq >> 8)
            .chr($this->seq);
        hash_update($hmac, $array);
        $this->seq++;

        return hash_final($hmac, true);
    }
}
