SecurityHelper::unmaskToken()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
namespace WebComplete\core\utils\helpers;
4
5
class SecurityHelper
6
{
7
8
    /**
9
     * @param string $password
10
     * @param string $salt
11
     *
12
     * @return string
13
     */
14
    public function cryptPassword(string $password, string $salt): string
15
    {
16
        return \strtoupper(\md5(\md5($salt) . \md5($password)));
17
    }
18
19
    /**
20
     * Masks a token to make it uncompressible.
21
     * Applies a random mask to the token and prepends the mask used to the result making the string always unique.
22
     * Used to mitigate BREACH attack by randomizing how token is outputted on each request.
23
     *
24
     * @param string $token An unmasked token.
25
     *
26
     * @return string A masked token.
27
     * @throws \RuntimeException
28
     */
29
    public function maskToken($token): string
30
    {
31
        // The number of bytes in a mask is always equal to the number of bytes in a token.
32
        $mask = $this->generateRandomKey(StringHelper::byteLength($token));
33
        return StringHelper::base64UrlEncode($mask . ($mask ^ $token));
34
    }
35
36
    /**
37
     * Unmasks a token previously masked by `maskToken`.
38
     * @param string $maskedToken A masked token.
39
     * @return string An unmasked token, or an empty string in case of token format is invalid.
40
     */
41
    public function unmaskToken($maskedToken): string
42
    {
43
        $decoded = StringHelper::base64UrlDecode($maskedToken);
44
        $length = StringHelper::byteLength($decoded) / 2;
45
        // Check if the masked token has an even length.
46
        if (!is_int($length)) {
0 ignored issues
show
introduced by
The condition is_int($length) is always true.
Loading history...
47
            return '';
48
        }
49
        return StringHelper::byteSubstr($decoded, $length, $length) ^
50
            StringHelper::byteSubstr($decoded, 0, $length);
51
    }
52
53
    /**
54
     * Generates specified number of random bytes.
55
     * Note that output may not be ASCII.
56
     *
57
     * @see generateRandomString() if you need a string.
58
     *
59
     * @param int $length the number of bytes to generate
60
     *
61
     * @return string the generated random bytes
62
     * @throws \RuntimeException
63
     */
64
    public function generateRandomKey(int $length = 32): string
65
    {
66
        if ($length < 1) {
67
            throw new \RuntimeException('First parameter ($length) must be greater than 0');
68
        }
69
70
        // always use random_bytes() if it is available
71
        if (\function_exists('random_bytes')) {
72
            return \random_bytes($length);
73
        }
74
        throw new \RuntimeException('Function random_bytes not found');
75
    }
76
77
    /**
78
     * Generates a random string of specified length.
79
     * The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding.
80
     *
81
     * @param int $length the length of the key in characters
82
     *
83
     * @return string the generated random key
84
     * @throws \RuntimeException
85
     */
86
    public function generateRandomString(int $length = 32): string
87
    {
88
        if ($length < 1) {
89
            throw new \RuntimeException('First parameter ($length) must be greater than 0');
90
        }
91
92
        $bytes = $this->generateRandomKey($length);
93
        return \substr(StringHelper::base64UrlEncode($bytes), 0, $length);
94
    }
95
}
96