Test Setup Failed
Push — master ( b88989...23c882 )
by smiley
09:01
created

CryptoSodium   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2
Metric Value
wmc 10
lcom 1
cbo 2
dl 0
loc 121
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A version() 0 4 1
A bin2hex() 0 4 1
A hex2bin() 0 4 1
A getRandomBytes() 0 4 1
A getKeypair() 0 16 1
B encrypt() 0 38 3
A decrypt() 0 23 2
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
use stdClass;
16
17
/**
18
 * 
19
 */
20
class CryptoSodium extends CryptoAbstract{
21
22
	public function version():string{
23
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
24
		return 'libsodium '.\Sodium\version_string();
25
	}
26
27
	/**
28
	 * @inheritdoc
29
	 */
30
	public function bin2hex(string $bin):string{
31
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
32
		return \Sodium\bin2hex($bin);
33
	}
34
35
	/**
36
	 * @inheritdoc
37
	 */
38
	public function hex2bin(string $hex):string{
39
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
40
		return \Sodium\hex2bin($hex);
41
	}
42
43
	/**
44
	 * @inheritdoc
45
	 */
46
	public function getRandomBytes(int $length):string{
47
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
48
		return \Sodium\randombytes_buf($length);
49
	}
50
51
	/**
52
	 * @inheritdoc
53
	 */
54
	public function getKeypair():stdClass{
55
		$pair = new stdClass;
56
57
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
58
		$keypair = \Sodium\crypto_box_keypair();
59
60
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
61
		$pair->privateKey = $this->bin2hex(\Sodium\crypto_box_secretkey($keypair));
62
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
63
		$pair->publicKey  = $this->bin2hex(\Sodium\crypto_box_publickey($keypair));
64
65
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
66
		\Sodium\memzero($keypair);
67
68
		return $pair;
69
	}
70
71
	/**
72
	 * @inheritdoc
73
	 */
74
	public function encrypt(string $data, string $privateKey, string $publicKey):stdClass {
75
76
		if(empty($data)){
77
			throw new CryptoException('invalid data');
78
		}
79
80
		if(!preg_match('/^[a-f\d]{128}$/i', $privateKey.$publicKey)){
81
			throw new CryptoException('invalid keypair');
82
		}
83
84
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
85
		$keypair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($this->hex2bin($privateKey), $this->hex2bin($publicKey));
86
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
87
		\Sodium\memzero($privateKey);
88
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
89
		\Sodium\memzero($publicKey);
90
91
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedConstantInspection */
92
		$nonce = $this->getRandomBytes(\Sodium\CRYPTO_BOX_NONCEBYTES);
93
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
94
		$box = \Sodium\crypto_box($data, $nonce, $keypair);
95
96
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
97
		\Sodium\memzero($keypair);
98
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
99
		\Sodium\memzero($data);
100
101
		$encrypted        = new \stdClass;
102
		$encrypted->nonce = $this->bin2hex($nonce);
103
		$encrypted->box   = $this->bin2hex($box);
104
105
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
106
		\Sodium\memzero($nonce);
107
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
108
		\Sodium\memzero($box);
109
110
		return $encrypted;
111
	}
112
113
	/**
114
	 * @inheritdoc
115
	 */
116
	public function decrypt(string $box, string $nonce, string $privateKey, string $publicKey):string{
117
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
118
		$keypair = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($this->hex2bin($privateKey), $this->hex2bin($publicKey));
119
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
120
		\Sodium\memzero($privateKey);
121
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
122
		\Sodium\memzero($publicKey);
123
124
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
125
		$data = \Sodium\crypto_box_open($this->hex2bin($box), $this->hex2bin($nonce), $keypair);
126
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
127
		\Sodium\memzero($keypair);
128
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
129
		\Sodium\memzero($box);
130
		/** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
131
		\Sodium\memzero($nonce);
132
133
		if(empty($data)){
134
			throw new CryptoException('decryption failed'); // @codeCoverageIgnore
135
		}
136
137
		return $data;
138
	}
139
140
}
141