RSA::rsaVerify()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Pasargad\Utils;
4
5
class RSA
6
{
7
    public const BCCOMP_LARGER = 1;
8
9
    public static function rsaEncrypt($message, $public_key, $modulus, $keylength)
10
    {
11
        $padded = RSA::addPKCS1Padding($message, true, $keylength / 8);
12
        $number = RSA::binaryToNumber($padded);
13
        $encrypted = RSA::powMod($number, $public_key, $modulus);
14
        $result = RSA::numberToBinary($encrypted, $keylength / 8);
15
        return $result;
16
    }
17
18
    public static function rsaDecrypt($message, $private_key, $modulus, $keylength)
19
    {
20
        $number = RSA::binaryToNumber($message);
21
        $decrypted = RSA::powMod($number, $private_key, $modulus);
22
        $result = RSA::numberToBinary($decrypted, $keylength / 8);
23
        return RSA::removePKCS1Padding($result, $keylength / 8);
24
    }
25
26
    public static function rsaSign($message, $private_key, $modulus, $keylength)
27
    {
28
        $padded = RSA::addPKCS1Padding($message, false, $keylength / 8);
29
        $number = RSA::binaryToNumber($padded);
30
        $signed = RSA::powMod($number, $private_key, $modulus);
31
        $result = RSA::numberToBinary($signed, $keylength / 8);
32
        return $result;
33
    }
34
35
    public static function rsaVerify($message, $public_key, $modulus, $keylength)
36
    {
37
        return RSA::rsaDecrypt($message, $public_key, $modulus, $keylength);
38
    }
39
40
    public static function rsaKypVerify($message, $public_key, $modulus, $keylength)
41
    {
42
        $number = RSA::binaryToNumber($message);
43
        $decrypted = RSA::powMod($number, $public_key, $modulus);
44
        $result = RSA::numberToBinary($decrypted, $keylength / 8);
45
        return RSA::removeKYPPadding($result, $keylength / 8);
46
    }
47
48
    public static function powMod($p, $q, $r)
49
    {
50
        $factors = array();
51
        $div = $q;
52
        $power_of_two = 0;
53
        while (bccomp($div, "0") == self::BCCOMP_LARGER) {
54
            $rem = bcmod($div, 2);
55
            $div = bcdiv($div, 2);
56
            if ($rem) {
57
                array_push($factors, $power_of_two);
58
            }
59
            $power_of_two++;
60
        }
61
        $partial_results = array();
62
        $part_res = $p;
63
        $idx = 0;
64
        foreach ($factors as $factor) {
65
            while ($idx < $factor) {
66
                $part_res = bcpow($part_res, "2");
67
                $part_res = bcmod($part_res, $r);
68
                $idx++;
69
            }
70
            array_push($partial_results, $part_res);
71
        }
72
        $result = "1";
73
        foreach ($partial_results as $part_res) {
74
            $result = bcmul($result, $part_res);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type null; however, parameter $num1 of bcmul() does only seem to accept string, 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
            $result = bcmul(/** @scrutinizer ignore-type */ $result, $part_res);
Loading history...
75
            $result = bcmod($result, $r);
76
        }
77
        return $result;
78
    }
79
80
    public static function addPKCS1Padding($data, $isPublicKey, $blocksize)
81
    {
82
        $pad_length = $blocksize - 3 - strlen($data);
83
        if ($isPublicKey) {
84
            $block_type = "\x02";
85
            $padding = "";
86
            for ($i = 0; $i < $pad_length; $i++) {
87
                $rnd = mt_rand(1, 255);
88
                $padding .= chr($rnd);
89
            }
90
        } else {
91
            $block_type = "\x01";
92
            $padding = str_repeat("\xFF", $pad_length);
93
        }
94
        return "\x00" . $block_type . $padding . "\x00" . $data;
95
    }
96
97
    public static function removePKCS1Padding($data, $blocksize)
98
    {
99
        assert(strlen($data) == $blocksize);
100
        $data = substr($data, 1);
101
        if ($data[0] == '\0') {
102
            die("Block type 0 not implemented.");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
103
        }
104
105
        assert(($data[0] == "\x01") || ($data[0] == "\x02"));
106
        $offset = strpos($data, "\0", 1);
107
        return substr($data, $offset + 1);
108
    }
109
110
    public static function removeKYPPadding($data, $blocksize)
111
    {
112
        assert(strlen($data) == $blocksize);
113
        $offset = strpos($data, "\0");
114
        return substr($data, 0, $offset);
115
    }
116
117
    public static function binaryToNumber($data)
118
    {
119
        $base = "256";
120
        $radix = "1";
121
        $result = "0";
122
        for ($i = strlen($data) - 1; $i >= 0; $i--) {
123
            $digit = ord($data[$i]);
124
            $part_res = bcmul($digit, $radix);
125
            $result = bcadd($result, $part_res);
126
            $radix = bcmul($radix, $base);
127
        }
128
        return $result;
129
    }
130
131
    public static function numberToBinary($number, $blocksize)
132
    {
133
        $base = "256";
134
        $result = "";
135
        $div = $number;
136
        while ($div > 0) {
137
            $mod = bcmod($div, $base);
138
            $div = bcdiv($div, $base);
139
            $result = chr($mod) . $result;
0 ignored issues
show
Bug introduced by
$mod of type null|string is incompatible with the type integer expected by parameter $codepoint of chr(). ( Ignorable by Annotation )

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

139
            $result = chr(/** @scrutinizer ignore-type */ $mod) . $result;
Loading history...
140
        }
141
        return str_pad($result, $blocksize, "\x00", STR_PAD_LEFT);
142
    }
143
}
144