Completed
Push — master ( e8e851...71a8c4 )
by BENOIT
06:28
created

Shh   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
wmc 16
lcom 2
cbo 1
dl 0
loc 121
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 3
A getPublicKeyAsResource() 0 9 3
A encrypt() 0 11 2
A decrypt() 0 24 5
A generateKeyPair() 0 15 3
1
<?php
2
3
namespace BenTools\Shh;
4
5
final class Shh
6
{
7
    private const DEFAULT_OPENSSL_GENERATION_CONFIGURATION = [
8
        'digest_alg'       => 'sha512',
9
        'private_key_bits' => 4096,
10
        'private_key_type' => \OPENSSL_KEYTYPE_RSA,
11
    ];
12
13
    /**
14
     * @var string
15
     */
16
    private $publicKey;
17
18
    /**
19
     * @var string|null
20
     */
21
    private $privateKey;
22
23
    /**
24
     * @var string|null
25
     */
26
    private $passphrase;
27
28
    /**
29
     * @var resource
30
     */
31
    private $resource;
32
33
    /**
34
     * Shh constructor.
35
     */
36
    public function __construct(string $publicKey, ?string $privateKey = null, ?string $passphrase = null)
37
    {
38
        $this->publicKey = (0 === \strpos($publicKey, '/')) ? 'file://' .$publicKey : $publicKey;
39
        $this->privateKey = (0 === \strpos($privateKey, '/')) ? 'file://' .$privateKey : $privateKey;
40
        $this->passphrase = $passphrase;
41
    }
42
43
    /**
44
     * @return resource
45
     */
46
    private function getPublicKeyAsResource()
47
    {
48
        if (null === $this->resource) {
49
            $this->resource = \openssl_pkey_get_public($this->publicKey)
50
                or ShhException::throwFromLastOpenSSLError('Unable to open resource.');
51
        }
52
53
        return $this->resource;
54
    }
55
56
    /**
57
     * @param string $payload
58
     * @return string
59
     * @throws \Pikirasa\Exception
60
     */
61
    public function encrypt(string $payload): string
62
    {
63
        $resource = $this->getPublicKeyAsResource();
64
        $success = \openssl_public_encrypt($payload, $encryptedData, $resource, \OPENSSL_PKCS1_OAEP_PADDING);
65
        \openssl_free_key($resource);
66
        if (!$success) {
67
            throw new ShhException("Encryption failed. Ensure you are using a PUBLIC key.");
68
        }
69
70
        return \base64_encode($encryptedData);
71
    }
72
73
    /**
74
     * @param string $base64EncodedPayload
75
     * @return string
76
     * @hrows \Pikirasa\Exception
77
     */
78
    public function decrypt(string $base64EncodedPayload): string
79
    {
80
        if (null === $this->privateKey) {
81
            throw new ShhException('Unable to decrypt payload: no private key provided.');
82
        }
83
84
        $payload = \base64_decode($base64EncodedPayload);
85
86
        if (false === $payload) {
87
            throw new ShhException('Encrypted payload was not provided as Base64.');
88
        }
89
90
        $resource = \openssl_pkey_get_private($this->privateKey, $this->passphrase)
91
            or ShhException::throwFromLastOpenSSLError('Private key seems corrupted.');
92
93
        $success = \openssl_private_decrypt($payload, $decryptedData, $resource, \OPENSSL_PKCS1_OAEP_PADDING);
94
        \openssl_free_key($resource);
95
96
        if (!$success) {
97
            throw new ShhException("Decryption failed. Ensure you are using (1) A PRIVATE key, and (2) the correct one.");
98
        }
99
100
        return $decryptedData;
101
    }
102
103
    /**
104
     * Generate a new private/public key pair.
105
     *
106
     * @param string|null $passphrase
107
     * @param array       $config
108
     * @return array - [privateKey, publicKey]
109
     */
110
    public static function generateKeyPair(?string $passphrase = null, array $config = self::DEFAULT_OPENSSL_GENERATION_CONFIGURATION)
111
    {
112
        $resource = \openssl_pkey_new($config)
113
            or ShhException::throwFromLastOpenSSLError('Unable to open resource.');
114
115
        $success = \openssl_pkey_export($resource, $privateKey, $passphrase);
116
117
        if (false === $success) {
118
            ShhException::throwFromLastOpenSSLError('Private key generation failed.');
119
        }
120
121
        $publicKey = \openssl_pkey_get_details($resource)['key'];
122
123
        return [$publicKey, $privateKey];
124
    }
125
}
126