1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Threema GmbH |
4
|
|
|
* @copyright Copyright (c) 2015-2016 Threema GmbH |
5
|
|
|
*/ |
6
|
|
|
|
7
|
|
|
|
8
|
|
|
namespace Threema\MsgApi\Tools; |
9
|
|
|
|
10
|
|
|
use Threema\Core\Exception; |
11
|
|
|
use Threema\Core\KeyPair; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Contains static methods to do various Threema cryptography related tasks. |
15
|
|
|
* Support libsodium >= 0.2.0 (Namespaces) |
16
|
|
|
* |
17
|
|
|
* @package Threema\Core |
18
|
|
|
*/ |
19
|
|
|
class CryptToolSodium extends CryptTool { |
20
|
|
|
/** |
21
|
|
|
* @param string $data |
22
|
|
|
* @param string $nonce |
23
|
|
|
* @param string $senderPrivateKey |
24
|
|
|
* @param string $recipientPublicKey |
25
|
|
|
* @return string encrypted box |
26
|
|
|
*/ |
27
|
|
|
protected function makeBox($data, $nonce, $senderPrivateKey, $recipientPublicKey) { |
28
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
29
|
|
|
$kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($senderPrivateKey, $recipientPublicKey); |
30
|
|
|
|
31
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
32
|
|
|
return \Sodium\crypto_box($data, $nonce, $kp); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* make a secret box |
37
|
|
|
* |
38
|
|
|
* @param $data |
39
|
|
|
* @param $nonce |
40
|
|
|
* @param $key |
41
|
|
|
* @return mixed |
42
|
|
|
*/ |
43
|
|
|
protected function makeSecretBox($data, $nonce, $key) { |
44
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
45
|
|
|
return \Sodium\crypto_secretbox($data, $nonce, $key); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @param string $box |
51
|
|
|
* @param string $recipientPrivateKey |
52
|
|
|
* @param string $senderPublicKey |
53
|
|
|
* @param string $nonce |
54
|
|
|
* @return null|string |
55
|
|
|
*/ |
56
|
|
|
protected function openBox($box, $recipientPrivateKey, $senderPublicKey, $nonce) { |
57
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
58
|
|
|
$kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($recipientPrivateKey, $senderPublicKey); |
59
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
60
|
|
|
return \Sodium\crypto_box_open($box, $nonce, $kp); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* decrypt a secret box |
65
|
|
|
* |
66
|
|
|
* @param string $box as binary |
67
|
|
|
* @param string $nonce as binary |
68
|
|
|
* @param string $key as binary |
69
|
|
|
* @return string as binary |
70
|
|
|
*/ |
71
|
|
|
protected function openSecretBox($box, $nonce, $key) { |
72
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
73
|
|
|
return \Sodium\crypto_secretbox_open($box, $nonce, $key); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Generate a new key pair. |
78
|
|
|
* |
79
|
|
|
* @return KeyPair the new key pair |
80
|
|
|
*/ |
81
|
|
|
final public function generateKeyPair() { |
82
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
83
|
|
|
$kp = \Sodium\crypto_box_keypair(); |
84
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
85
|
|
|
return new KeyPair(\Sodium\crypto_box_secretkey($kp), \Sodium\crypto_box_publickey($kp)); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @param int $size |
90
|
|
|
* @return string |
91
|
|
|
*/ |
92
|
|
|
protected function createRandom($size) { |
93
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
94
|
|
|
return \Sodium\randombytes_buf($size); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Derive the public key |
99
|
|
|
* |
100
|
|
|
* @param string $privateKey in binary |
101
|
|
|
* @return string public key as binary |
102
|
|
|
*/ |
103
|
|
|
final public function derivePublicKey($privateKey) { |
104
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
105
|
|
|
return \Sodium\crypto_box_publickey_from_secretkey($privateKey); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Converts a binary string to an hexdecimal string. |
110
|
|
|
* |
111
|
|
|
* This is the same as PHP's bin2hex() implementation, but it is resistant to |
112
|
|
|
* timing attacks. |
113
|
|
|
* |
114
|
|
|
* @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#bin2hex |
115
|
|
|
* @param string $binaryString The binary string to convert |
116
|
|
|
* @return string |
117
|
|
|
*/ |
118
|
|
|
public function bin2hex($binaryString) |
119
|
|
|
{ |
120
|
|
|
return \Sodium\bin2hex($binaryString); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Converts an hexdecimal string to a binary string. |
125
|
|
|
* |
126
|
|
|
* This is the same as PHP's hex2bin() implementation, but it is resistant to |
127
|
|
|
* timing attacks. |
128
|
|
|
* |
129
|
|
|
* @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#hex2bin |
130
|
|
|
* @param string $hexString The hex string to convert |
131
|
|
|
* @param string|null $ignore (optional) Characters to ignore |
132
|
|
|
* @throws \Threema\Core\Exception |
133
|
|
|
* @return string |
134
|
|
|
*/ |
135
|
|
|
public function hex2bin($hexString, $ignore = null) |
136
|
|
|
{ |
137
|
|
|
return \Sodium\hex2bin($hexString, $ignore); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Compares two strings in a secure way. |
143
|
|
|
* |
144
|
|
|
* This is the same as PHP's strcmp() implementation, but it is resistant to |
145
|
|
|
* timing attacks. |
146
|
|
|
* |
147
|
|
|
* @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#compare |
148
|
|
|
* @param string $str1 The first string |
149
|
|
|
* @param string $str2 The second string |
150
|
|
|
* @return bool |
151
|
|
|
*/ |
152
|
|
|
public function stringCompare($str1, $str2) |
153
|
|
|
{ |
154
|
|
|
// check variable type manually |
155
|
|
|
if (!is_string($str1) || !is_string($str2)) { |
156
|
|
|
return false; |
|
|
|
|
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
return \Sodium\memcmp($str1, $str2) === 0; |
|
|
|
|
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Check if implementation supported |
164
|
|
|
* @return bool |
165
|
|
|
*/ |
166
|
|
|
public function isSupported() { |
167
|
|
|
return true === extension_loaded('libsodium') |
168
|
|
|
&& false === method_exists('Sodium', 'sodium_version_string'); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Validate crypt tool |
173
|
|
|
* |
174
|
|
|
* @return bool |
175
|
|
|
* @throws Exception |
176
|
|
|
*/ |
177
|
|
|
public function validate() { |
178
|
|
|
if(false === $this->isSupported()) { |
179
|
|
|
throw new Exception('Sodium implementation not supported'); |
180
|
|
|
} |
181
|
|
|
return true; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @return string |
186
|
|
|
*/ |
187
|
|
|
public function getName() { |
188
|
|
|
return 'sodium'; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Description of the CryptTool |
193
|
|
|
* @return string |
194
|
|
|
*/ |
195
|
|
|
public function getDescription() { |
196
|
|
|
/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */ |
197
|
|
|
return 'Sodium implementation '.\Sodium\version_string(); |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.