Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
66.67% |
10 / 15 |
CRAP | |
83.64% |
46 / 55 |
| PayloadCypher | |
0.00% |
0 / 1 |
|
66.67% |
10 / 15 |
21.75 | |
83.64% |
46 / 55 |
| setOnPrivateKeyLoad | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| setOnPublicKeyLoad | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| binToArmor | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| armorToBin | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| setPublicKey | |
0.00% |
0 / 1 |
2.01 | |
85.71% |
6 / 7 |
|||
| setPrivateKey | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| setChunkDelimiter | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| setKeyName | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| encryptString | |
0.00% |
0 / 1 |
3.00 | |
92.86% |
13 / 14 |
|||
| decryptString | |
0.00% |
0 / 1 |
3.00 | |
92.31% |
12 / 13 |
|||
| objectToEncryptedJson | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| encryptedJsonToObject | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| arrayToEncryptedJson | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| encryptedJsonToArray | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| encryptedJsonDump | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
| <?php | |
| namespace Dataground; | |
| use Closure; | |
| use ErrorException; | |
| use stdClass; | |
| /** | |
| * Class PayloadCypher | |
| * | |
| * @author Dataground <info@dataground.com> | |
| */ | |
| class PayloadCypher | |
| { | |
| /** | |
| * @var string | |
| */ | |
| private $keyName = 'TMP'; | |
| /** | |
| * @var string | |
| */ | |
| private $publicKey = ''; | |
| /** | |
| * @var string | |
| */ | |
| private $privateKey = ''; | |
| /** | |
| * @var string | |
| */ | |
| private $chunkDelimiter = "_"; | |
| /** | |
| * @var int | |
| */ | |
| private $chunkLen = 0; | |
| /** | |
| * Replace base64 chars to be "url safe" | |
| * @var array | |
| */ | |
| private $replaceChars = array('/' => '.x', '=' => '.y', '+' => '.z'); | |
| /** | |
| * @var Closure[] | |
| */ | |
| private $events = array( | |
| 'onPublicKeyLoad' => null, | |
| 'onPrivateKeyLoad' => null | |
| ); | |
| /** | |
| * @param Closure $onPrivateKeyLoad | |
| * | |
| * function loadPrivateKey($keyName) { | |
| * return array('... Name of Key ...' => '... PEM Private Key...'); | |
| * } | |
| */ | |
| public function setOnPrivateKeyLoad(Closure $onPrivateKeyLoad) | |
| { | |
| $this->events['onPrivateKeyLoad'] = $onPrivateKeyLoad; | |
| } | |
| /** | |
| * @param Closure $onPublicKeyLoad | |
| * | |
| * function loadPublicKey() { | |
| * return array('... Name of key ...' => '... PEM Public Key ...'); | |
| * } | |
| */ | |
| public function setOnPublicKeyLoad(Closure $onPublicKeyLoad) | |
| { | |
| $this->events['onPublicKeyLoad'] = $onPublicKeyLoad; | |
| } | |
| /** | |
| * @param $data | |
| * @return string | |
| */ | |
| public function binToArmor($data) | |
| { | |
| return str_replace(array_keys($this->replaceChars), $this->replaceChars, base64_encode($data)); | |
| } | |
| /** | |
| * @param $data | |
| * @return string | |
| */ | |
| public function armorToBin($data) | |
| { | |
| return base64_decode(str_replace($this->replaceChars, array_keys($this->replaceChars), $data)); | |
| } | |
| /** | |
| * Needed for encryption support | |
| * @param $publicKey | |
| * @throws ErrorException | |
| */ | |
| private function setPublicKey($publicKey) | |
| { | |
| $res = openssl_get_publickey($publicKey); | |
| if ($res === false) { | |
| throw new ErrorException('Error while opening public key ' . openssl_error_string()); | |
| } | |
| // RSA is only able to encrypt data to a maximum amount of your key size (2048 bits = 256 bytes) minus padding / header data (11 bytes for PKCS#1 v1.5 padding). | |
| // https://polarssl.org/kb/cryptography/rsa-encryption-maximum-data-size | |
| $keyData = openssl_pkey_get_details($res); | |
| $this->chunkLen = ($keyData['bits'] / 8) - 11; | |
| $this->publicKey = $publicKey; | |
| } | |
| /** | |
| * Needed for decryption support | |
| * @param string $privateKey | |
| */ | |
| private function setPrivateKey($privateKey) | |
| { | |
| $this->privateKey = $privateKey; | |
| } | |
| /** | |
| * @param string $chunkDelimiter | |
| */ | |
| public function setChunkDelimiter($chunkDelimiter) | |
| { | |
| $this->chunkDelimiter = $chunkDelimiter; | |
| } | |
| /** | |
| * @param string $keyName | |
| */ | |
| public function setKeyName($keyName) | |
| { | |
| $this->keyName = $keyName; | |
| } | |
| /** | |
| * @param $payload | |
| * @return string | |
| * @throws ErrorException | |
| */ | |
| public function encryptString($payload) | |
| { | |
| $keyArray = $this->events['onPublicKeyLoad'](); | |
| $keyCrt = reset($keyArray); | |
| $keyName = key($keyArray); | |
| $this->setKeyName($keyName); | |
| $this->setPublicKey($keyCrt); | |
| // @todo check all prereqs | |
| $parts = str_split($payload, $this->chunkLen); | |
| $encryptedParts = array($this->keyName); | |
| foreach ($parts as $part) { | |
| $ok = openssl_public_encrypt($part, $encryptedPart, $this->publicKey); | |
| if ($ok === false) { | |
| throw new ErrorException('Error while encrypting chunk ' . openssl_error_string()); | |
| } | |
| $encryptedParts[] = $this->binToArmor($encryptedPart); | |
| } | |
| return join($this->chunkDelimiter, $encryptedParts); | |
| } | |
| /** | |
| * @param $cryptedPayload | |
| * @return string | |
| * @throws ErrorException | |
| */ | |
| public function decryptString($cryptedPayload) | |
| { | |
| $parts = explode($this->chunkDelimiter, $cryptedPayload); | |
| $keyName = array_shift($parts); | |
| $keyArray = $this->events['onPrivateKeyLoad']($keyName); | |
| $this->setPrivateKey(reset($keyArray)); | |
| $out = ''; | |
| foreach ($parts as $part) { | |
| $decrypted = ''; | |
| $ok = openssl_private_decrypt($this->armorToBin($part), $decrypted, $this->privateKey); | |
| if ($ok === false) { | |
| throw new ErrorException('Error while decrypting chunk: ' . openssl_error_string()); | |
| } | |
| $out .= $decrypted; | |
| } | |
| return $out; | |
| } | |
| /** | |
| * @todo large file encryption/decryption streaming to outfile | |
| */ | |
| // public function encryptFile($inFile, $outFile) { | |
| // } | |
| // public function decryptFile($inFile, $outFile) { | |
| // } | |
| /** | |
| * @param stdClass $data | |
| * @return string | |
| */ | |
| public function objectToEncryptedJson(stdClass $data) | |
| { | |
| return $this->encryptString(json_encode($data)); | |
| } | |
| /** | |
| * @param $encryptedJson | |
| * @return stdClass $object | |
| * @throws ErrorException | |
| */ | |
| public function encryptedJsonToObject($encryptedJson) | |
| { | |
| return json_decode($this->decryptString($encryptedJson), false); | |
| } | |
| /** | |
| * @param array $data | |
| * @return string | |
| * @throws ErrorException | |
| */ | |
| public function arrayToEncryptedJson(array $data = array()) | |
| { | |
| return $this->encryptString(json_encode($data)); | |
| } | |
| /** | |
| * @param $encryptedJson | |
| * @param array $mergeTo | |
| * @return array | |
| * @throws ErrorException | |
| */ | |
| public function encryptedJsonToArray($encryptedJson, array $mergeTo = array()) | |
| { | |
| $data = json_decode($this->decryptString($encryptedJson), true); | |
| return array_merge($mergeTo, $data); | |
| } | |
| /** | |
| * @param $encryptedJson | |
| * @throws ErrorException | |
| */ | |
| public function encryptedJsonDump($encryptedJson) | |
| { | |
| echo '---' . PHP_EOL; | |
| echo $this->decryptString($encryptedJson) . PHP_EOL; | |
| echo '---' . PHP_EOL; | |
| } | |
| } |