PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / lib / packages / Cose / Algorithm / Signature / RSA / PSSRSA.php

PSSRSA.php in Defender Security – Malware Scanner, Login Security & Firewall 6.3.0, at lib/packages/Cose/Algorithm/Signature/RSA/PSSRSA.php

182 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 /*
6 * The MIT License (MIT)
7 *
8 * Copyright (c) 2014-2021 Spomky-Labs
9 *
10 * This software may be modified and distributed under the terms
11 * of the MIT license. See the LICENSE file for details.
12 */
13
14 namespace WP_DEFENDER_VENDOR\Cose\Algorithm\Signature\RSA;
15
16 use function ceil;
17 use function chr;
18 use WP_DEFENDER_VENDOR\Cose\Algorithm\Signature\Signature;
19 use WP_DEFENDER_VENDOR\Cose\BigInteger;
20 use WP_DEFENDER_VENDOR\Cose\Hash;
21 use WP_DEFENDER_VENDOR\Cose\Key\Key;
22 use WP_DEFENDER_VENDOR\Cose\Key\RsaKey;
23 use function hash_equals;
24 use InvalidArgumentException;
25 use function mb_strlen;
26 use function mb_substr;
27 use function ord;
28 use function random_bytes;
29 use RuntimeException;
30 use function str_pad;
31 use function str_repeat;
32
33 /**
34 * @internal
35 */
36 abstract class PSSRSA implements Signature
37 {
38 public function sign(string $data, Key $key): string
39 {
40 $key = $this->handleKey($key);
41 $modulusLength = mb_strlen($key->n(), '8bit');
42
43 $em = $this->encodeEMSAPSS($data, 8 * $modulusLength - 1, $this->getHashAlgorithm());
44 $message = BigInteger::createFromBinaryString($em);
45 $signature = $this->exponentiate($key, $message);
46
47 return $this->convertIntegerToOctetString($signature, $modulusLength);
48 }
49
50 public function verify(string $data, Key $key, string $signature): bool
51 {
52 $key = $this->handleKey($key);
53 $modulusLength = mb_strlen($key->n(), '8bit');
54
55 if (mb_strlen($signature, '8bit') !== $modulusLength) {
56 throw new InvalidArgumentException('Invalid modulus length');
57 }
58 $s2 = BigInteger::createFromBinaryString($signature);
59 $m2 = $this->exponentiate($key, $s2);
60 $em = $this->convertIntegerToOctetString($m2, $modulusLength);
61 $modBits = 8 * $modulusLength;
62
63 return $this->verifyEMSAPSS($data, $em, $modBits - 1, $this->getHashAlgorithm());
64 }
65
66 /**
67 * Exponentiate with or without Chinese Remainder Theorem.
68 * Operation with primes 'p' and 'q' is appox. 2x faster.
69 */
70 public function exponentiate(RsaKey $key, BigInteger $c): BigInteger
71 {
72 if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare(BigInteger::createFromBinaryString($key->n())) > 0) {
73 throw new RuntimeException();
74 }
75 if ($key->isPublic() || !$key->hasPrimes() || !$key->hasExponents() || !$key->hasCoefficient()) {
76 return $c->modPow(BigInteger::createFromBinaryString($key->e()), BigInteger::createFromBinaryString($key->n()));
77 }
78
79 [$p, $q] = $key->primes();
80 [$dP, $dQ] = $key->exponents();
81 $qInv = BigInteger::createFromBinaryString($key->QInv());
82
83 $m1 = $c->modPow($dP, $p);
84 $m2 = $c->modPow($dQ, $q);
85 $h = $qInv->multiply($m1->subtract($m2)->add($p))->mod($p);
86
87 return $m2->add($h->multiply($q));
88 }
89
90 abstract protected function getHashAlgorithm(): Hash;
91
92 private function handleKey(Key $key): RsaKey
93 {
94 return new RsaKey($key->getData());
95 }
96
97 private function convertIntegerToOctetString(BigInteger $x, int $xLen): string
98 {
99 $x = $x->toBytes();
100 if (mb_strlen($x, '8bit') > $xLen) {
101 throw new RuntimeException('Unable to convert the integer');
102 }
103
104 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
105 }
106
107 /**
108 * MGF1.
109 */
110 private function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string
111 {
112 $t = '';
113 $count = ceil($maskLen / $mgfHash->getLength());
114 for ($i = 0; $i < $count; ++$i) {
115 $c = pack('N', $i);
116 $t .= $mgfHash->hash($mgfSeed.$c);
117 }
118
119 return mb_substr($t, 0, $maskLen, '8bit');
120 }
121
122 /**
123 * EMSA-PSS-ENCODE.
124 */
125 private function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string
126 {
127 $emLen = ($modulusLength + 1) >> 3;
128 $sLen = $hash->getLength();
129 $mHash = $hash->hash($message);
130 if ($emLen <= $hash->getLength() + $sLen + 2) {
131 throw new RuntimeException();
132 }
133 $salt = random_bytes($sLen);
134 $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
135 $h = $hash->hash($m2);
136 $ps = str_repeat(chr(0), $emLen - $sLen - $hash->getLength() - 2);
137 $db = $ps.chr(1).$salt;
138 $dbMask = $this->getMGF1($h, $emLen - $hash->getLength() - 1, $hash);
139 $maskedDB = $db ^ $dbMask;
140 $maskedDB[0] = ~chr(0xFF << ($modulusLength & 7)) & $maskedDB[0];
141
142 return $maskedDB.$h.chr(0xBC);
143 }
144
145 /**
146 * EMSA-PSS-VERIFY.
147 */
148 private function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool
149 {
150 $emLen = ($emBits + 1) >> 3;
151 $sLen = $hash->getLength();
152 $mHash = $hash->hash($m);
153 if ($emLen < $hash->getLength() + $sLen + 2) {
154 throw new InvalidArgumentException();
155 }
156 if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) {
157 throw new InvalidArgumentException();
158 }
159 $maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit');
160 $h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit');
161 $temp = chr(0xFF << ($emBits & 7));
162 if ((~$maskedDB[0] & $temp) !== $temp) {
163 throw new InvalidArgumentException();
164 }
165 $dbMask = $this->getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/);
166 $db = $maskedDB ^ $dbMask;
167 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
168 $temp = $emLen - $hash->getLength() - $sLen - 2;
169 if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(chr(0), $temp)) {
170 throw new InvalidArgumentException();
171 }
172 if (1 !== ord($db[$temp])) {
173 throw new InvalidArgumentException();
174 }
175 $salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long
176 $m2 = "\0\0\0\0\0\0\0\0".$mHash.$salt;
177 $h2 = $hash->hash($m2);
178
179 return hash_equals($h, $h2);
180 }
181 }
182