CryptoSodium::createBox()   B
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 16
nc 3
nop 3
1
<?php
2
/**
3
 * Class CryptoSodium
4
 *
5
 * @filesource   CryptoSodium.php
6
 * @created      01.04.2016
7
 * @package      chillerlan\Threema\Crypto
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2016 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\Threema\Crypto;
14
15
class CryptoSodium extends CryptoAbstract{
16
17
	/**
18
	 * @inheritdoc
19
	 */
20
	public function version():string{
21
		return 'libsodium '.\Sodium\version_string();
22
	}
23
24
	/**
25
	 * @inheritdoc
26
	 */
27
	public function bin2hex(string $bin):string{
28
		return \Sodium\bin2hex($bin);
29
	}
30
31
	/**
32
	 * @inheritdoc
33
	 */
34
	public function hex2bin(string $hex):string{
35
		return \Sodium\hex2bin($hex);
36
	}
37
38
	/**
39
	 * @inheritdoc
40
	 */
41
	public function getRandomBytes(int $length):string{
42
		return \Sodium\randombytes_buf($length);
43
	}
44
45
	/**
46
	 * @inheritdoc
47
	 */
48
	public function getKeypair():array {
49
		$keypair = \Sodium\crypto_box_keypair();
50
51
		$pair = [
52
			'public'  => $this->bin2hex(\Sodium\crypto_box_publickey($keypair)),
53
			'private' => $this->bin2hex(\Sodium\crypto_box_secretkey($keypair)),
54
		];
55
56
		\Sodium\memzero($keypair);
57
58
		return $pair;
59
	}
60
61
	/**
62
	 * @inheritdoc
63
	 */
64
	public function createBox(string $data, string $privateKey, string $publicKey):array {
65
66
		if(empty($data)){
67
			throw new CryptoException('invalid data');
68
		}
69
70
		if(!preg_match('/^[a-f\d]{128}$/i', $privateKey.$publicKey)){
71
			throw new CryptoException('invalid keypair');
72
		}
73
74
		$keypair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($this->hex2bin($privateKey), $this->hex2bin($publicKey));
75
76
		\Sodium\memzero($privateKey);
77
		\Sodium\memzero($publicKey);
78
79
		$nonce = $this->getRandomBytes(\Sodium\CRYPTO_BOX_NONCEBYTES);
80
		$box = \Sodium\crypto_box($data, $nonce, $keypair);
81
82
		\Sodium\memzero($keypair);
83
		\Sodium\memzero($data);
84
85
		$encrypted = ['box' => $this->bin2hex($box), 'nonce' => $this->bin2hex($nonce)];
86
87
		\Sodium\memzero($nonce);
88
		\Sodium\memzero($box);
89
90
		return $encrypted;
91
	}
92
93
	/**
94
	 * @inheritdoc
95
	 */
96
	public function openBox(string $box, string $nonce, string $privateKey, string $publicKey):string{
97
98
		$keypair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey(
99
			$this->hex2bin($privateKey),
100
			$this->hex2bin($publicKey)
101
		);
102
103
		\Sodium\memzero($privateKey);
104
		\Sodium\memzero($publicKey);
105
106
		$data = \Sodium\crypto_box_open($this->hex2bin($box), $this->hex2bin($nonce), $keypair);
107
108
		\Sodium\memzero($keypair);
109
		\Sodium\memzero($box);
110
		\Sodium\memzero($nonce);
111
112
		if(empty($data)){
113
			throw new CryptoException('decryption failed'); // @codeCoverageIgnore
114
		}
115
116
		return $data;
117
	}
118
119
	/**
120
	 * @inheritdoc
121
	 */
122
	public function createSecretBox(string $data, string $nonce, string $key):string{
123
		$box = \Sodium\crypto_secretbox($data, $nonce, $key);
124
125
		\Sodium\memzero($data);
126
		\Sodium\memzero($nonce);
127
		\Sodium\memzero($key);
128
129
		return $box;
130
	}
131
132
	/**
133
	 * @inheritdoc
134
	 */
135
	public function openSecretBox(string $box, string $nonce, string $key):string{
136
		$data = \Sodium\crypto_secretbox_open($box, $nonce, $key);
137
138
		\Sodium\memzero($box);
139
		\Sodium\memzero($nonce);
140
		\Sodium\memzero($key);
141
142
		return $data;
143
	}
144
145
}
146