Completed
Push — master ( e2a574...def6ae )
by Jan
02:45
created

CryptoService   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 8
c 3
b 1
f 0
lcom 2
cbo 5
dl 0
loc 97
rs 10

3 Methods

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