HmacRandomNumberGenerator::generate()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 34
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 5
eloc 23
c 6
b 0
f 0
nc 5
nop 1
dl 0
loc 34
rs 9.2408
1
<?php
2
declare(strict_types=1);
3
4
namespace Mdanter\Ecc\Random;
5
6
use Mdanter\Ecc\Crypto\Key\PrivateKeyInterface;
7
use Mdanter\Ecc\Math\GmpMathInterface;
8
use Mdanter\Ecc\Util\BinaryString;
9
use Mdanter\Ecc\Util\NumberSize;
10
11
class HmacRandomNumberGenerator implements RandomNumberGeneratorInterface
12
{
13
    /**
14
     * @var GmpMathInterface
15
     */
16
    private $math;
17
18
    /**
19
     * @var string
20
     */
21
    private $algorithm;
22
23
    /**
24
     * @var PrivateKeyInterface
25
     */
26
    private $privateKey;
27
28
    /**
29
     * @var \GMP
30
     */
31
    private $messageHash;
32
33
    /**
34
     * @var array
35
     */
36
    private $algSize = array(
37
        'sha1' => 160,
38
        'sha224' => 224,
39
        'sha256' => 256,
40
        'sha384' => 384,
41
        'sha512' => 512
42
    );
43
44
    /**
45
     * Hmac constructor.
46
     * @param GmpMathInterface $math
47
     * @param PrivateKeyInterface $privateKey
48
     * @param \GMP $messageHash - decimal hash of the message (*may* be truncated)
49
     * @param string $algorithm - hashing algorithm
50
     */
51
    public function __construct(GmpMathInterface $math, PrivateKeyInterface $privateKey, \GMP $messageHash, string $algorithm)
52
    {
53
        if (!isset($this->algSize[$algorithm])) {
54
            throw new \InvalidArgumentException('Unsupported hashing algorithm');
55
        }
56
57
        $this->math = $math;
58
        $this->algorithm = $algorithm;
59
        $this->privateKey = $privateKey;
60
        $this->messageHash = $messageHash;
61
    }
62
63
    /**
64
     * @param string $bits - binary string of bits
65
     * @param \GMP $qlen - length of q in bits
66
     * @return \GMP
67
     */
68
    public function bits2int(string $bits, \GMP $qlen): \GMP
69
    {
70
        $vlen = gmp_init(BinaryString::length($bits) * 8, 10);
71
        $hex = bin2hex($bits);
72
        $v = gmp_init($hex, 16);
73
74
        if ($this->math->cmp($vlen, $qlen) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $vlen can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMathInterface::cmp() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

74
        if ($this->math->cmp(/** @scrutinizer ignore-type */ $vlen, $qlen) > 0) {
Loading history...
75
            $v = $this->math->rightShift($v, (int) $this->math->toString($this->math->sub($vlen, $qlen)));
0 ignored issues
show
Bug introduced by
It seems like $v can also be of type resource; however, parameter $number of Mdanter\Ecc\Math\GmpMathInterface::rightShift() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

75
            $v = $this->math->rightShift(/** @scrutinizer ignore-type */ $v, (int) $this->math->toString($this->math->sub($vlen, $qlen)));
Loading history...
Bug introduced by
It seems like $vlen can also be of type resource; however, parameter $minuend of Mdanter\Ecc\Math\GmpMathInterface::sub() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

75
            $v = $this->math->rightShift($v, (int) $this->math->toString($this->math->sub(/** @scrutinizer ignore-type */ $vlen, $qlen)));
Loading history...
76
        }
77
78
        return $v;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $v could return the type resource which is incompatible with the type-hinted return GMP. Consider adding an additional type-check to rule them out.
Loading history...
79
    }
80
81
    /**
82
     * @param \GMP $int
83
     * @param \GMP $rlen - rounded octet length
84
     * @return string
85
     */
86
    public function int2octets(\GMP $int, \GMP $rlen): string
87
    {
88
        $out = pack("H*", $this->math->decHex(gmp_strval($int, 10)));
89
        $length = gmp_init(BinaryString::length($out), 10);
90
        if ($this->math->cmp($length, $rlen) < 0) {
0 ignored issues
show
Bug introduced by
It seems like $length can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMathInterface::cmp() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
        if ($this->math->cmp(/** @scrutinizer ignore-type */ $length, $rlen) < 0) {
Loading history...
91
            return str_pad('', (int) $this->math->toString($this->math->sub($rlen, $length)), "\x00") . $out;
0 ignored issues
show
Bug introduced by
It seems like $length can also be of type resource; however, parameter $subtrahend of Mdanter\Ecc\Math\GmpMathInterface::sub() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

91
            return str_pad('', (int) $this->math->toString($this->math->sub($rlen, /** @scrutinizer ignore-type */ $length)), "\x00") . $out;
Loading history...
92
        }
93
94
        if ($this->math->cmp($length, $rlen) > 0) {
95
            return BinaryString::substring($out, 0, (int) $this->math->toString($rlen));
96
        }
97
98
        return $out;
99
    }
100
101
    /**
102
     * @param string $algorithm
103
     * @return int
104
     */
105
    private function getHashLength(string $algorithm): int
106
    {
107
        return $this->algSize[$algorithm];
108
    }
109
110
    /**
111
     * @param \GMP $q
112
     * @return \GMP
113
     */
114
    public function generate(\GMP $q): \GMP
115
    {
116
        $qlen = gmp_init(NumberSize::bnNumBits($this->math, $q), 10);
117
        $rlen = $this->math->rightShift($this->math->add($qlen, gmp_init(7, 10)), 3);
0 ignored issues
show
Bug introduced by
It seems like gmp_init(7, 10) can also be of type resource; however, parameter $addend of Mdanter\Ecc\Math\GmpMathInterface::add() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
        $rlen = $this->math->rightShift($this->math->add($qlen, /** @scrutinizer ignore-type */ gmp_init(7, 10)), 3);
Loading history...
Bug introduced by
It seems like $qlen can also be of type resource; however, parameter $augend of Mdanter\Ecc\Math\GmpMathInterface::add() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
        $rlen = $this->math->rightShift($this->math->add(/** @scrutinizer ignore-type */ $qlen, gmp_init(7, 10)), 3);
Loading history...
118
        $hlen = $this->getHashLength($this->algorithm);
119
        $bx = $this->int2octets($this->privateKey->getSecret(), $rlen) . $this->int2octets($this->messageHash, $rlen);
120
121
        $v = str_pad('', $hlen >> 3, "\x01", STR_PAD_LEFT);
122
        $k = str_pad('', $hlen >> 3, "\x00", STR_PAD_LEFT);
123
124
        $k = hash_hmac($this->algorithm, $v . "\x00" . $bx, $k, true);
125
        $v = hash_hmac($this->algorithm, $v, $k, true);
126
127
        $k = hash_hmac($this->algorithm, $v . "\x01" . $bx, $k, true);
128
        $v = hash_hmac($this->algorithm, $v, $k, true);
129
130
        $t = '';
131
        for (;;) {
132
            $toff = gmp_init(0, 10);
133
            while ($this->math->cmp($toff, $rlen) < 0) {
0 ignored issues
show
Bug introduced by
It seems like $toff can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMathInterface::cmp() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

133
            while ($this->math->cmp(/** @scrutinizer ignore-type */ $toff, $rlen) < 0) {
Loading history...
134
                $v = hash_hmac($this->algorithm, $v, $k, true);
135
136
                $cc = min(BinaryString::length($v), (int) gmp_strval(gmp_sub($rlen, $toff), 10));
137
                $t .= BinaryString::substring($v, 0, $cc);
138
                $toff = gmp_add($toff, $cc);
139
            }
140
141
            $k = $this->bits2int($t, $qlen);
0 ignored issues
show
Bug introduced by
It seems like $qlen can also be of type resource; however, parameter $qlen of Mdanter\Ecc\Random\HmacR...erGenerator::bits2int() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
            $k = $this->bits2int($t, /** @scrutinizer ignore-type */ $qlen);
Loading history...
142
            if ($this->math->cmp($k, gmp_init(0, 10)) > 0 && $this->math->cmp($k, $q) < 0) {
0 ignored issues
show
Bug introduced by
It seems like gmp_init(0, 10) can also be of type resource; however, parameter $other of Mdanter\Ecc\Math\GmpMathInterface::cmp() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

142
            if ($this->math->cmp($k, /** @scrutinizer ignore-type */ gmp_init(0, 10)) > 0 && $this->math->cmp($k, $q) < 0) {
Loading history...
143
                return $k;
144
            }
145
146
            $k = hash_hmac($this->algorithm, $v . "\x00", $k, true);
0 ignored issues
show
Bug introduced by
$k of type GMP is incompatible with the type string expected by parameter $key of hash_hmac(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
            $k = hash_hmac($this->algorithm, $v . "\x00", /** @scrutinizer ignore-type */ $k, true);
Loading history...
147
            $v = hash_hmac($this->algorithm, $v, $k, true);
148
        }
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return GMP. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
149
    }
150
}
151