getJsonPayload($payload); // We'll go ahead and remove the PKCS7 padding from the encrypted value before // we decrypt it. Once we have the de-padded value, we will grab the vector // and decrypt the data, passing back the unserialized from of the value. $value = base64_decode($payload['value']); $iv = base64_decode($payload['iv']); return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv))); } protected function getJsonPayload($payload) { $payload = json_decode(base64_decode($payload), true); // If the payload is not valid JSON or does not have the proper keys set we will // assume it is invalid and bail out of the routine since we will not be able // to decrypt the given value. We'll also check the MAC for this encryption. if ( ! $payload || $this->invalidPayload($payload)) { var_dump('Invalid data.'); } if ( ! $this->validMac($payload)) { var_dump('MAC is invalid.'); } return $payload; } protected function validMac(array $payload) { $bytes = (new SecureRandom)->nextBytes(16); $calcMac = hash_hmac('sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true); return StringUtils::equals(hash_hmac('sha256', $payload['mac'], $bytes, true), $calcMac); } protected function stripPadding($value) { $pad = ord($value[($len = strlen($value)) - 1]); return $this->paddingIsValid($pad, $value) ? substr($value, 0, $len - $pad) : $value; } protected function mcryptDecrypt($value, $iv) { try { return mcrypt_decrypt($this->cipher, $this->key, $value, $this->mode, $iv); } catch (Exception $e) { var_dump($e->getMessage()); die; } } protected function invalidPayload($data) { return ! is_array($data) || ! isset($data['iv']) || ! isset($data['value']) || ! isset($data['mac']); } protected function paddingIsValid($pad, $value) { $beforePad = strlen($value) - $pad; return substr($value, $beforePad) == str_repeat(substr($value, -1), $pad); } protected function hash($iv, $value) { return hash_hmac('sha256', $iv.$value, $this->key); } }