1 | <?php declare(strict_types = 1); |
||
2 | |||
3 | namespace SlevomatCsobGateway\Crypto; |
||
4 | |||
5 | use const OPENSSL_ALGO_SHA256; |
||
6 | use function base64_decode; |
||
7 | use function base64_encode; |
||
8 | use function file_get_contents; |
||
9 | |||
10 | class CryptoService |
||
11 | { |
||
12 | |||
13 | public const HASH_METHOD = OPENSSL_ALGO_SHA256; |
||
14 | |||
15 | /** @var string */ |
||
16 | private $privateKeyFile; |
||
17 | |||
18 | /** @var string */ |
||
19 | private $bankPublicKeyFile; |
||
20 | |||
21 | /** @var string|null */ |
||
22 | private $privateKeyPassword; |
||
23 | |||
24 | 6 | public function __construct( |
|
25 | string $privateKeyFile, |
||
26 | string $bankPublicKeyFile, |
||
27 | string $privateKeyPassword = '' |
||
28 | ) |
||
29 | { |
||
30 | 6 | $this->privateKeyFile = $privateKeyFile; |
|
31 | 6 | $this->bankPublicKeyFile = $bankPublicKeyFile; |
|
32 | 6 | $this->privateKeyPassword = $privateKeyPassword; |
|
33 | 6 | } |
|
34 | |||
35 | /** |
||
36 | * @param mixed[] $data |
||
37 | * @param SignatureDataFormatter $signatureDataFormatter |
||
38 | * @return string |
||
39 | * |
||
40 | * @throws PrivateKeyFileException |
||
41 | * @throws SigningFailedException |
||
42 | */ |
||
43 | 4 | public function signData(array $data, SignatureDataFormatter $signatureDataFormatter): string |
|
44 | { |
||
45 | 4 | $message = $signatureDataFormatter->formatDataForSignature($data); |
|
46 | |||
47 | /** @var string $privateKey */ |
||
48 | 4 | $privateKey = file_get_contents($this->privateKeyFile); |
|
49 | 4 | $privateKeyId = openssl_pkey_get_private($privateKey, (string) $this->privateKeyPassword); |
|
50 | 4 | if ($privateKeyId === false) { |
|
51 | 1 | throw new PrivateKeyFileException($this->privateKeyFile); |
|
52 | } |
||
53 | |||
54 | 3 | $ok = openssl_sign($message, $signature, $privateKeyId, self::HASH_METHOD); |
|
55 | 3 | if (!$ok) { |
|
0 ignored issues
–
show
introduced
by
![]() |
|||
56 | 1 | throw new SigningFailedException($data); |
|
57 | } |
||
58 | |||
59 | 2 | $signature = base64_encode($signature); |
|
60 | 2 | openssl_free_key($privateKeyId); |
|
61 | |||
62 | 2 | return $signature; |
|
63 | } |
||
64 | |||
65 | /** |
||
66 | * @param mixed[] $data |
||
67 | * @param string $signature |
||
68 | * @param SignatureDataFormatter $signatureDataFormatter |
||
69 | * @return bool |
||
70 | * |
||
71 | * @throws PublicKeyFileException |
||
72 | * @throws VerificationFailedException |
||
73 | */ |
||
74 | 4 | public function verifyData(array $data, string $signature, SignatureDataFormatter $signatureDataFormatter): bool |
|
75 | { |
||
76 | 4 | $message = $signatureDataFormatter->formatDataForSignature($data); |
|
77 | |||
78 | 4 | $publicKey = (string) file_get_contents($this->bankPublicKeyFile); |
|
79 | 4 | $publicKeyId = openssl_pkey_get_public($publicKey); |
|
80 | 4 | if ($publicKeyId === false) { |
|
81 | 1 | throw new PublicKeyFileException($this->bankPublicKeyFile); |
|
82 | } |
||
83 | |||
84 | 3 | $signature = base64_decode($signature, true); |
|
85 | 3 | if ($signature === false) { |
|
86 | throw new VerificationFailedException($data, 'Unable to decode signature.'); |
||
87 | } |
||
88 | |||
89 | 3 | $verifyResult = openssl_verify($message, $signature, $publicKeyId, self::HASH_METHOD); |
|
90 | 3 | openssl_free_key($publicKeyId); |
|
91 | 3 | if ($verifyResult === -1) { |
|
92 | 1 | throw new VerificationFailedException($data, openssl_error_string()); |
|
93 | } |
||
94 | |||
95 | 2 | return $verifyResult === 1; |
|
96 | } |
||
97 | |||
98 | } |
||
99 |