123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- <?php
- namespace Elliptic;
- class HmacDRBG
- {
- private $hash;
- private $predResist;
- private $outLen;
- private $minEntropy;
- private $reseed;
- private $reseedInterval;
- private $K;
- private $V;
- function __construct($options)
- {
- Utils::optionAssert($options, "predResist");
- Utils::optionAssert($options, "hash", null, true);
- Utils::optionAssert($options["hash"], "outSize", null, true);
- Utils::optionAssert($options["hash"], "hmacStrength", null, true);
- Utils::optionAssert($options["hash"], "algo", null, true);
- Utils::optionAssert($options, "minEntropy");
- Utils::optionAssert($options, "entropy", null, true);
- Utils::optionAssert($options, "entropyEnc");
- Utils::optionAssert($options, "nonce", "");
- Utils::optionAssert($options, "nonceEnc");
- Utils::optionAssert($options, "pers", "");
- Utils::optionAssert($options, "persEnc");
- $this->hash = $options["hash"];
- $this->predResist = $options["predResist"];
- $this->outLen = $this->hash["outSize"];
- $this->minEntropy = $options["minEntropy"] ?: $this->hash["hmacStrength"];
- $this->reseed = null;
- $this->reseedInterval = null;
- $this->K = null;
- $this->V = null;
- $entropy = Utils::toBin($options["entropy"], $options["entropyEnc"]);
- $nonce = Utils::toBin($options["nonce"], $options["nonceEnc"]);
- $pers = Utils::toBin($options["pers"], $options["persEnc"]);
-
- if (assert_options(ASSERT_ACTIVE)) {
- assert(strlen($entropy) >= ($this->minEntropy / 8));
- }
- $this->_init($entropy, $nonce, $pers);
- }
- private function _init($entropy, $nonce, $pers)
- {
- $seed = $entropy . $nonce . $pers;
- $this->K = str_repeat(chr(0x00), $this->outLen / 8);
- $this->V = str_repeat(chr(0x01), $this->outLen / 8);
- $this->_update($seed);
- $this->reseed = 1;
- $this->reseedInterval = 0x1000000000000; // 2^48
- }
- private function _hmac()
- {
- return hash_init($this->hash["algo"], HASH_HMAC, $this->K);
- }
- private function _update($seed = false)
- {
- $kmac = $this->_hmac();
- hash_update($kmac, $this->V);
- hash_update($kmac, chr(0x00));
- if( $seed )
- hash_update($kmac, $seed);
- $this->K = hash_final($kmac, true);
- $kmac = $this->_hmac();
- hash_update($kmac, $this->V);
- $this->V = hash_final($kmac, true);
- if(!$seed)
- return;
- $kmac = $this->_hmac();
- hash_update($kmac, $this->V);
- hash_update($kmac, chr(0x01));
- hash_update($kmac, $seed);
- $this->K = hash_final($kmac, true);
- $kmac = $this->_hmac();
- hash_update($kmac, $this->V);
- $this->V = hash_final($kmac, true);
- }
- // TODO: reseed()
- public function generate($len, $enc = null, $add = null, $addEnc = null)
- {
- if ($this->reseed > $this->reseedInterval)
- throw new \Exception("Reseed is required");
- // Optional encoding
- if( !is_string($enc) )
- {
- $addEnc = $enc;
- $add = $enc;
- $enc = null;
- }
- // Optional additional data
- if( $add != null ) {
- $add = Utils::toBin($add, $addEnc);
- $this->_update($add);
- }
- $temp = "";
- while( strlen($temp) < $len )
- {
- $hmac = $this->_hmac();
- hash_update($hmac, $this->V);
- $this->V = hash_final($hmac, true);
- $temp .= $this->V;
- }
- $res = substr($temp, 0, $len);
- $this->_update($add);
- $this->reseed++;
- return Utils::encode(Utils::toArray($res), $enc);
- }
- }
- ?>
|