Completed
Push — master ( badd30...b58b91 )
by Lawrence
02:30 queued 01:02
created

Signer::encode()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 5
Bugs 1 Features 0
Metric Value
c 5
b 1
f 0
dl 0
loc 27
ccs 0
cts 14
cp 0
rs 8.8571
cc 3
eloc 14
nc 4
nop 1
crap 12
1
<?php
2
3
namespace Plinker\Core;
4
5
use phpseclib\Crypt\AES;
6
use Plinker\Base91\Base91;
7
8
/**
9
 * Payload signing class.
10
 */
11
class Signer
12
{
13
    /**
14
     * @var
15
     */
16
    private $publicKey;
17
18
    /**
19
     * @var
20
     */
21
    private $privateKey;
22
23
    /**
24
     * @var
25
     */
26
    private $encrypt;
27
28
    /**
29
     * @var
30
     */
31
    private $encryption;
32
33
    /**
34
     * @var
35
     */
36
    private $packet_state;
37
38
    /**
39
     * Construct.
40
     *
41
     * @param string $publicKey
42
     * @param string $privateKey
43
     */
44 4
    public function __construct($publicKey = null, $privateKey = null, $encrypt = true)
45
    {
46 4
        $this->publicKey = $publicKey;
47 4
        $this->privateKey = $privateKey;
48 4
        $this->encrypt = $encrypt;
49
50
        // set encryption
51 4
        if ($this->encrypt) {
52 4
            $this->encryption = new AES(/* ECB */ 1);
53 4
            $this->encryption->setPassword($this->privateKey);
54
        }
55 4
    }
56
57
    /**
58
     * Payload encode/encrypt
59
     * Encodes and signs the payload packet.
60
     *
61
     * @param array $signer
62
     * @return array
63
     */
64
    public function encode($packet = [])
65
    {
66
        // serialize response data
67
        if (!empty($packet['response'])) {
68
            $packet['response'] = serialize($packet['response']);
69
        }
70
71
        // set time into packet
72
        $packet['time'] = microtime(true);
73
74
        $data = serialize($packet);
75
76
        $packet = [
77
            'data'         => ($this->encrypt ? Base91::encode($this->encryption->encrypt($data)) : $data),
78
            'public_key'   => $this->publicKey,
79
            'time'         => microtime(true),
80
            'encrypt'      => $this->encrypt,
81
        ];
82
83
        // sign packet
84
        $packet['token'] = hash_hmac(
85
            'sha256',
86
            $packet['data'],
87
            $this->privateKey
88
        );
89
90
        return $packet;
91
    }
92
93
    /**
94
     * Payload decode/decrypt
95
     * Validates and decodes payload packet.
96
     *
97
     * @param array $signer
98
     * @return mixed
99
     */
100
    public function decode($packet = [])
101
    {
102
        // failed packet validation
103
        if (!$this->authenticatePacket($packet)) {
104
            // unset not needed response vars
105
            unset($packet['data']);
106
            unset($packet['public_key']);
107
            unset($packet['token']);
108
            unset($packet['encrypt']);
109
110
            $packet['response'] = serialize(['error' => $this->packet_state]);
111
112
            return $packet;
113
        }
114
115
        if ($this->encrypt) {
116
            $packet['data'] = $this->encryption->decrypt(Base91::decode($packet['data']));
117
        }
118
119
        return unserialize($packet['data']);
120
    }
121
122
    /**
123
     * Authenticate payload packet.
124
     *
125
     * @param array $packet
126
     * @return bool
127
     */
128
    public function authenticatePacket($packet = [])
129
    {
130
        $this->packet_state = 'valid';
131
132
        // public key required
133
        if (empty($packet['public_key'])) {
134
            $this->packet_state = 'public key required';
135
136
            return false;
137
        }
138
139
        // token required
140
        if (empty($packet['token'])) {
141
            $this->packet_state = 'token required';
142
143
            return false;
144
        }
145
146
        // data required
147
        if (empty($packet['data'])) {
148
            $this->packet_state = 'empty data';
149
150
            return false;
151
        }
152
153
        // authenticate packet signature/token
154
        if (hash_hmac(
155
            'sha256',
156
            $packet['data'],
157
            $this->privateKey
158
        ) == $packet['token']) {
159
            return true;
160
        } else {
161
            $this->packet_state = 'unauthorised';
162
163
            return false;
164
        }
165
    }
166
}
167