Completed
Pull Request — master (#42)
by rugk
07:19
created

CryptToolSodium   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
lcom 0
cbo 3
dl 0
loc 181
rs 10
c 1
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A makeBox() 0 7 1
A makeSecretBox() 0 4 1
A openBox() 0 6 1
A openSecretBox() 0 4 1
A generateKeyPair() 0 6 1
A createRandom() 0 4 1
A derivePublicKey() 0 4 1
A bin2hex() 0 4 1
A hex2bin() 0 4 1
A stringCompare() 0 9 3
A isSupported() 0 4 2
A validate() 0 6 2
A getName() 0 3 1
A getDescription() 0 4 1
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;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method Threema\MsgApi\Tools\CryptTool::stringCompare of type integer.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
157
		}
158
159
		return \Sodium\memcmp($str1, $str2) === 0;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \Sodium\memcmp($str1, $str2) === 0; (boolean) is incompatible with the return type of the parent method Threema\MsgApi\Tools\CryptTool::stringCompare of type integer.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
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