Decryptor.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. <?php
  2. namespace RNCryptor\RNCryptor;
  3. use stdClass;
  4. /**
  5. * RNDecryptor for PHP
  6. *
  7. * Decrypt data interchangeably with Rob Napier's Objective-C implementation
  8. * of RNCryptor
  9. */
  10. class Decryptor extends Cryptor
  11. {
  12. /**
  13. * Decrypt RNCryptor-encrypted data
  14. *
  15. * @param string $base64EncryptedData Encrypted, Base64-encoded text
  16. * @param string $password Password the text was encoded with
  17. * @throws Exception If the detected version is unsupported
  18. * @return string|false Decrypted string, or false if decryption failed
  19. */
  20. public function decrypt($encryptedBase64Data, $password)
  21. {
  22. $components = $this->unpackEncryptedBase64Data($encryptedBase64Data);
  23. if (!$this->hmacIsValid($components, $password)) {
  24. return false;
  25. }
  26. $key = $this->makeKey($components->headers->encSalt, $password);
  27. if ($this->config->mode == 'ctr') {
  28. return $this->aesCtrLittleEndianCrypt($components->ciphertext, $key, $components->headers->iv);
  29. }
  30. $iv = (string)$components->headers->iv;
  31. $method = $this->config->algorithm . 'cbc';
  32. return openssl_decrypt($components->ciphertext, $method, $key, OPENSSL_RAW_DATA, (string)$iv);
  33. }
  34. private function unpackEncryptedBase64Data($encryptedBase64Data, $isPasswordBased = true)
  35. {
  36. $binaryData = base64_decode($encryptedBase64Data);
  37. $components = new stdClass;
  38. $components->headers = $this->parseHeaders($binaryData, $isPasswordBased);
  39. $components->hmac = substr($binaryData, -$this->config->hmac->length);
  40. $offset = $components->headers->length;
  41. $length = strlen($binaryData) - $offset - strlen($components->hmac);
  42. $components->ciphertext = substr($binaryData, $offset, $length);
  43. return $components;
  44. }
  45. private function parseHeaders($binData, $isPasswordBased = true)
  46. {
  47. $offset = 0;
  48. $versionChr = $binData[0];
  49. $offset += strlen($versionChr);
  50. $this->configure(ord($versionChr));
  51. $optionsChr = $binData[1];
  52. $offset += strlen($optionsChr);
  53. $encSalt = null;
  54. $hmacSalt = null;
  55. if ($isPasswordBased) {
  56. $encSalt = substr($binData, $offset, $this->config->saltLength);
  57. $offset += strlen($encSalt);
  58. $hmacSalt = substr($binData, $offset, $this->config->saltLength);
  59. $offset += strlen($hmacSalt);
  60. }
  61. $iv = substr($binData, $offset, $this->config->ivLength);
  62. $offset += strlen($iv);
  63. $headers = (object)[
  64. 'version' => $versionChr,
  65. 'options' => $optionsChr,
  66. 'encSalt' => $encSalt,
  67. 'hmacSalt' => $hmacSalt,
  68. 'iv' => $iv,
  69. 'length' => $offset
  70. ];
  71. return $headers;
  72. }
  73. private function hmacIsValid($components, $password)
  74. {
  75. $hmacKey = $this->makeKey($components->headers->hmacSalt, $password);
  76. return hash_equals($components->hmac, $this->makeHmac($components, $hmacKey));
  77. }
  78. }