HmacTokenProvider::getToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of the Linna Csrf Guard.
7
 *
8
 * @author Sebastian Rapetti <[email protected]>
9
 * @copyright (c) 2020, Sebastian Rapetti
10
 * @license http://opensource.org/licenses/MIT MIT License
11
 */
12
13
namespace Linna\CsrfGuard\Provider;
14
15
use Linna\CsrfGuard\Exception\BadExpireException;
16
use Linna\CsrfGuard\Exception\BadExpireTrait;
17
18
/**
19
 * Csrf HMAC Based Token Pattern Provider.
20
 *
21
 * <p>It uses hash_hmac with sha3-384 algorithm and doesn't need storage to work.</p>
22
 */
23
class HmacTokenProvider implements TokenProviderInterface
24
{
25
    use BadExpireTrait;
26
27
    /**
28
     * Class constructor.
29
     *
30
     * @param string $value  Value will be hashed inside token.
31
     * @param string $key    Secret key for the hmac.
32
     * @param int    $expire Token validity in seconds, default 600 -> 10 minutes.
33
     *
34
     * @throws BadExpireException If <code>$expire</code> is less than 0 and greater than 86400.
35
     */
36
    public function __construct(
37
        /** @var string $key Secret key for the hmac. */
38
        private string $value,
39
        /** @var string $value Value will be hashed inside token. */
40
        private string $key,
41
        /** @var int $expire Token validity in seconds, default 600 -> 10 minutes. */
42
        private int $expire = 600
43
    ) {
44
        // from BadExpireTrait
45
        /** @throws BadExpireException */
46
        $this->checkBadExpire($expire);
47
48
        $this->key = $key;
49
        $this->value = $value;
50
        $this->expire = $expire;
51
    }
52
53
    /**
54
     * Return new Hmac Token.
55
     *
56
     * @return string The token in hex format.
57
     */
58
    public function getToken(): string
59
    {
60
        //get the time for the token
61
        $time = \dechex(\time());
62
        //random bytes for avoid to wait one second to get a different token
63
        $random = \bin2hex(\random_bytes(2));
64
65
        //return the token
66
        return \hash_hmac('sha3-384', $this->value.$time.$random, $this->key).$time.$random;
67
    }
68
69
    /**
70
     * Validate Hmac Token.
71
     *
72
     * @param string $token Token must be validated.
73
     *
74
     * @return bool True if the token is valid, false otherwise.
75
     */
76
    public function validate(string $token): bool
77
    {
78
        //check for void token
79
        if ($token === "") {
80
            return false;
81
        }
82
83
        //hmac present in token
84
        $hmac_token = \substr($token, 0, 96);
85
        //token time
86
        $time = \substr($token, 96, 8);
87
        //random value
88
        $random = \substr($token, 104);
89
90
        //hmac generate locally with token time
91
        $hmac_local = \hash_hmac('sha3-384', $this->value.$time.$random, $this->key);
92
93
        //hmac check in constant time
94
        if (!\hash_equals($hmac_local, $hmac_token)) {
95
            return false;
96
        }
97
98
        //timestamp from token time
99
        $timestamp = \hexdec($time);
100
101
        //token expiration check
102
        if ($timestamp + $this->expire < \time()) {
103
            return false;
104
        }
105
106
        return true;
107
    }
108
}
109