DecryptAes.php 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | WeChatDeveloper
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2014~2023 ThinkAdmin [ thinkadmin.top ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: https://thinkadmin.top
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( https://mit-license.org )
  10. // | 免责声明 ( https://thinkadmin.top/disclaimer )
  11. // +----------------------------------------------------------------------
  12. // | gitee 代码仓库:https://gitee.com/zoujingli/WeChatDeveloper
  13. // | github 代码仓库:https://github.com/zoujingli/WeChatDeveloper
  14. // +----------------------------------------------------------------------
  15. namespace WePayV3\Contracts;
  16. use WeChat\Exceptions\InvalidArgumentException;
  17. use WeChat\Exceptions\InvalidDecryptException;
  18. /**
  19. * Aes 解密工具类
  20. * Class DecryptAes
  21. * @package WePayV3\Contracts
  22. */
  23. class DecryptAes
  24. {
  25. private $aesKey;
  26. const KEY_LENGTH_BYTE = 32;
  27. const AUTH_TAG_LENGTH_BYTE = 16;
  28. /**
  29. * Constructor
  30. * @param string $aesKey
  31. */
  32. public function __construct($aesKey)
  33. {
  34. if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
  35. throw new InvalidArgumentException('无效的ApiV3Key,长度应为32个字节');
  36. }
  37. $this->aesKey = $aesKey;
  38. }
  39. /**
  40. * Decrypt AEAD_AES_256_GCM ciphertext
  41. * @param string $associatedData AES GCM additional authentication data
  42. * @param string $nonceStr AES GCM nonce
  43. * @param string $ciphertext AES GCM cipher text
  44. * @return string|bool Decrypted string on success or FALSE on failure
  45. * @throws \WeChat\Exceptions\InvalidDecryptException
  46. */
  47. public function decryptToString($associatedData, $nonceStr, $ciphertext)
  48. {
  49. $ciphertext = \base64_decode($ciphertext);
  50. if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
  51. return false;
  52. }
  53. try {
  54. // ext-sodium (default installed on >= PHP 7.2)
  55. if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
  56. return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
  57. }
  58. // ext-libsodium (need install libsodium-php 1.x via pecl)
  59. if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {
  60. return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
  61. }
  62. // openssl (PHP >= 7.1 support AEAD)
  63. if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
  64. $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
  65. $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
  66. return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData);
  67. }
  68. } catch (\Exception $exception) {
  69. throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
  70. } catch (\SodiumException $exception) {
  71. throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
  72. }
  73. throw new InvalidDecryptException('AEAD_AES_256_GCM 需要 PHP 7.1 以上或者安装 libsodium-php');
  74. }
  75. }