微信API V3 平臺證書解密失敗,返回false,如何解決?

acvc225發表於2021-01-13

安裝官方文件說明的,要先獲取平臺證照列表,然後再進行解密,獲取方法如下:

微信API V3 平臺證照解密
圖片中User-Agent後面備註的使用者代理(https://zh.wikipedia.org/wiki/User_agent)不知道是幹嘛的..

按照之前的簽名方法,最後獲得Authiorization值,放到header頭中,header頭引數如下:

$headers[] = 'Content-Type:application/json';
$headers[] = 'Accept:application/json';
$headers[] = 'User-Agent:'.$_SERVER['HTTP_USER_AGENT'];
$headers[] = 'Authorization:WECHATPAY2-SHA256-RSA2048 '.$token;

獲得證照列表如下:
微信API V3 平臺證照解密

為方便後面說明問題,我這裡把data資料整個貼出來

{
    "data": [
        {
            "effective_time": "2020-08-20T14:59:52+08:00",
            "encrypt_certificate": {
                "algorithm": "AEAD_AES_256_GCM",
                "associated_data": "certificate",
                "ciphertext": "io6eoAWJH1rb8GJ04aJ6LBUu059j2VhWpoi3Odaez1ngOHVdNPH4bHRLRji6Bdb3QTYWgF0L9Zjdjc/Zbt5dC10ixd8KlB1ZvRDaJ4nSSmVdJ0L92i3ORHJmKHsWVbt8+ZaM2Kg+vfDLRqnoZ4/YnL4PPi/U5bXovvFIzvOcvb6u6hXdq8+Ad7Ms4iOilKJyOiDNMci7HlC+h4elp5UvbebITMEG4OdzexHi8PEcrcRYEODFygzd0SDvOj5sQGjRTqtpA71o55gD0AKTtud3SH856y/N/2GIcmHArB7U5Q5zXQQQ8Fz14KA5bas7snqMMlqv/6c4aFsQjA1Di2Dm1+/E2aMHWn4UpDAohV4X5+MSHHfDdtsIfnvsgKwLjzTKXSe2d/FEjPYgtf/p6GwptGTJFbrk4octETAMpVIE8c2lUq6E8ekf+PqCYLT5njin8z6CBK/7PC4DrR195vTf/pOikyEV6fqc3/iety39y2LCgvDzL/0rz40thvHz4uBNqaxtnTo2SJlouR4D3qi+dmjO4XMWyPAZXpxxboV9PCQAufSGF65tSO8pRGPZiD76mNCyRi8nYeZtL3HFg4afXZeObAzQMJnxaMRsn7jObS+pibgbK45oUfmuoq8yEBUuvqvf5O3JPqKyI4QVqmYg0H07U9ueCWR/iHlsEsSwMG9Hjy4SvW5wPGYGdW9mio21YOl1uucTkS2b+szILnSaJ3oWoTb417qjoGI6Bt6ZWRRZAOmJsJGkzDTv1din0Wg/vRUpFFS/HI466E6yjEbORC8sPL1oze9qx2KsgML6GcUABdWcUXXqzScXxhFufeIkdqj2hG+I+ElNwlpuY/FKd6pqM29BP5up+EtazsABMjEb3e+WHbrwzmzY5c+uRwozd/Z15SKjYtgzOTK0HKbmyOBccA+5moFIt42Alwci3UIUYc5KStdywT42iCc++FtE+Dzu5R0spFFnEj9g9gbw8HzWWL2SCHoYOSsyFegz1QGYiJYAILdIle0IyFD2+PZGNbcdXzE6y2VS6GREhnRmn6QMfb83L7xUTQQf43NdsgXLb+XHGwtn0tZqH+vsMKn1hi0wmelqIsxHv+CvFKg/f7HoRd52vZ6i+uIfXE2nR1dHbygMtlZan47D45g3ZT+lI+0ECojFQI9IuGxRP35n3Sv4yjEvSIbs3+BTEYWZs6gmCyyK2vIm58j8TkTtuyGC5s4ExKl2o3Qfw1mUUg6WKzfnc4iup9Q8JsRNyH+/ra4FvATODvRZakAqlsaV079E+FRu73D+4lq92ZBST/XnGW2jrxuOxGsI2Q9AHiOZWoIFXVZp8DtBaFj/hGEAgN0atv53At/KdrM5Y+x7zx6v9NGOKkFnkw7LuJsARwj6pVSoh2cOQ9tJzCeeSQF985+q66Bmq6Kq51oMnyEzMe+HoOxeUEcTvLfCwteAcJzG/AkZwkwvnXLCcRBpc4ZEEfJtzwSasqdYapE/jexHG1fCQXcuqtdJUeXtxIBBMeTwLEBwed6pGjNw1tmDyNRN2fOzPX7FXbjgek8CJZC4oSStp7tuMIYkoV0RbmDBiSXV0QdOQ5vXgZw4WPalWv32gYhXG8yg8EE6MbPP4Pl8TpFm1CfCpWz2MVS5PyzY/2+lMfGuE3QK5IURbbZsILZJSY6e9TS9stquZEm4hnYB1syzTIf2+dL3GoFOQ45risIUcO68pTo4uBvKm2elpYTtiiQuwxj+0aKwLAilCGy3khNEdZfreWQaTuM///Pu5CkuBbCCYoevJEQnvX7U1HWRDJ1BjVE5Dqc23m2ThQ4exgihvikA4D2RnvGMpBhSJ71kD1kuPMCw+pQLvPFTKS/lOsH9cDZR+Gulvk29TTZ01EtjaQCbwrn6YQ==",
                "nonce": "aacc84fbf399"
            },
            "expire_time": "2025-08-19T14:59:52+08:00",
        }
    ]
}

下面開始看官方文件裡證照和回撥報文解密的部分,看到官方有提供整個解密操作的php程式碼,這裡也全部貼出來,如下:

class AesUtil{
  /**
    * AES key
    *
    * @var string
    */
  private $aesKey;

  const KEY_LENGTH_BYTE = 32;
  const AUTH_TAG_LENGTH_BYTE = 16;

  /**
    * Constructor
    */
  public function __construct($aesKey)
  {
      if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
          throw new InvalidArgumentException('無效的ApiV3Key,長度應為32個位元組');
      }
      $this->aesKey = $aesKey;
  }

  /**
    * Decrypt AEAD_AES_256_GCM ciphertext
    *
    * @param string    $associatedData     AES GCM additional authentication data
    * @param string    $nonceStr           AES GCM nonce
    * @param string    $ciphertext         AES GCM cipher text
    *
    * @return string|bool      Decrypted string on success or FALSE on failure
    */
  public function decryptToString($associatedData, $nonceStr, $ciphertext)
  {
      $ciphertext = \base64_decode($ciphertext);
      if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
          return false;
      }

      // ext-sodium (default installed on >= PHP 7.2)
      if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
          \sodium_crypto_aead_aes256gcm_is_available()) {
          return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
      }

      // ext-libsodium (need install libsodium-php 1.x via pecl)
      if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
          \Sodium\crypto_aead_aes256gcm_is_available()) {
          return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
      }

      // openssl (PHP >= 7.1 support AEAD)
      if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
          $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
          $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);

          $rs = \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
              $authTag, $associatedData);
          var_dump($rs);exit;  // 列印出解密結果
          return $rs;
      }

      throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安裝libsodium-php');
  }
}

這個類很簡單,主要是用到3個引數:$associatedData, $nonceStr, $ciphertext,還有一個初始化類的時候用到的API V3的祕鑰,這個是在商戶後臺的API安全裡配置的。
我直接把官方提供的這個類原封不動的拷過來,然後在控制器方法中引用這個類:

$aesutil = new AesUtilController($apiv3Key);
$rs = $aesutil->decryptToString($associatedData,$nonce,$ciphertext);

四個引數:
$apiv3Key 我在商戶後臺-API安全裡配置的祕鑰;
$associatedData 就是上面data資料裡的associated_data值”certificate”;
$nonce 就是上面data資料裡的nonce值”aacc84fbf399”;
$ciphertext 就是上面data資料裡的nonce值”ciphertext”;

全部配置好後,執行測試,返回bool(false),解密失敗!

想不明白,問題出在哪裡,一共就4個引數,$apiv3Key是固定值,不會有問題,其他3個引數都是從平臺api獲取的,應該也不會錯的啊?
嘗試線上base64解碼”ciphertext”的值,結果是亂碼:

微信API V3 平臺證照解密失敗,返回false,如何解決?
一臉懵逼!不知道是本來就應該是亂碼還是我獲取的”ciphertext”值是有問題的?又或者是我中間漏了什麼操作?
又研究了一下官方的程式碼,看到sodium_crypto_aead_aes256gcm_decrypt這個方法不能使用,於是又百度,看到需要開啟php.ini裡的extension=php_sodium.dll,發現裡面沒有這行程式碼,於是直接寫進去了,再到php安裝目錄下檢視libsodium.dll檔案是存在的,再到ext目錄下檢查php_sodium.dll檔案也在存在的,最後phpinfo(),看到sodium配置成功了。

再次嘗試執行,仍然返回bool(false),解密還是失敗!

至此,我基本是沒得辦法了。。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章