收藏
回答

服务端api签名指南,PHP版本有人成功过的吗?

框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
小程序 Bug https://api.weixin.qq.com/cgi-bin/express/intracity/addorder?access_token={ACCESS_TOKEN} 微信安卓客户端 6.5.3 2.0.0

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.htmlhttps://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.htmlhttps://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html

我这里加密后,解密有时候成功,有时候返回false,有人知道怎么回事,问微信官方,官方也是一问三不知,搞了快一周还没解决这个问题。

 //服务端api加密
    public static function getRequestParam($url, $req)
    {
        $key = base64_decode(self::apiAES256['key']);
        $sn = self::apiAES256['sn'];
        $appId = self::miniAppID;
        $time = time();
        //16位随机字符
        $nonce = rtrim(base64_encode(random_bytes(16)), '=');
        $nonce = base64_encode(random_bytes(16));
        $addReq = ["_n" => $nonce, "_appid" => $appId, "_timestamp" => $time];
        $realReq = array_merge($addReq, $req);
        ksort($realReq);
        $realReq = json_encode($realReq);
        //额外参数
        $aad = $url . "|" . $appId . "|" . $time . "|" . $sn;
        //12位随机字符
        $iv = random_bytes(12);
        //var_dump($iv);
        $cipher = openssl_encrypt($realReq, "aes-256-gcm", $key, 1, $iv, $tag, $aad);
        echo '<br>---------encrypt paras start-------------<br>';
        echo '<pre>';
        echo '$realReq:';
        var_dump($realReq);
        echo '$key:';
        var_dump($key);
        echo '$iv:';
        var_dump(base64_encode($iv));
        echo '$tag:';
        var_dump(base64_encode($tag));
        echo '$aad:';
        var_dump($aad);
         echo '<br>--------- encrypt paras end-------------<br>';
        $iv = base64_encode($iv);
        $data = base64_encode($cipher);
        $authTag = base64_encode($tag);
        $reqData = ["iv" => $iv, "data" => $data, "authtag" => $authTag];
        //校验本地加密是否正确 非必须
        //$checkParam = self::checkParam($key, $authTag, $iv, $data, $aad);
        return ['ts' => $time, 'reqData' => json_encode($reqData)];
    }
    
    //服务端api签名,$newRe参数是经过服务端api加密后的请求参数
    public static function sign(array $newRe, $url_path)
    {
        $time = $newRe['ts'];
        $key = self::apiRSA256['private_key'];
        $url = $url_path;
        $appId = self::miniAppID;
        $reqData = $newRe['reqData'];
        $payload = "$url\n$appId\n$time\n$reqData";
        $rsa = new RSA();
        $rsa->loadKey($key);
        $rsa->setHash("sha256");
        $rsa->setMGFHash("sha256");
        $signature = $rsa->sign($payload);
        return base64_encode($signature);
    }
    
    
    //服务端验对api返回的加密的结果进行解密,得到真实返回
    public static function jM($ts, $body, $url_path)
    {
         echo '<br>---------decrypt paras start-------------<br>';
        echo '<pre>';
        echo '$ts:';
        var_dump($ts);
        echo '$body:';
        var_dump($body);
        echo '$url_path:';
        var_dump($url_path);
         echo '<br>--------- decrypt paras end-------------<br>';
         
        $url = $url_path;
        $appId = self::miniAppID;;
        $sn = self::apiAES256['sn'];
        $aad = $url . '|' . $appId . '|' . $ts . '|' . $sn;
        $key = self::apiAES256['key'];
        $key = base64_decode($key);
        $iv = base64_decode($body['iv']);
        $data = $body['data'];
        // if (strlen($data) % 16) {
        //     $data = str_pad($data,strlen($data) + 16 - strlen($data) % 16, "\0");
        // }
        $data = base64_decode($data);
        $tag = base64_decode($body['authtag']);
        //print_r($tag);
        //print_r($data);
        $result = openssl_decrypt($data, "aes-256-gcm", $key, 1, $iv, $tag, $aad);
        var_dump( openssl_error_string());
        var_dump($result);
        if (!$result) {
            print_r(openssl_error_string());
            while ($msg = openssl_error_string())
                {
                    echo "<br>ERROR: " . $msg;
                } 
        }
        //$result = \Qiniu\json_decode($result,true);
        return $result;


    }


回答关注问题邀请回答
收藏

2 个回答

  • 大毛
    大毛
    2023-08-24

    头次见你这种echo方式的,你是在吐网页,还是在吐数据!

    2023-08-24
    有用
    回复
  • Ray
    Ray
    2023-08-24

    你的问题可能是由于在加密和解密过程中使用的随机生成的初始化向量(IV)或者认证标签(auth tag)不一致导致的。在你的代码中,你在加密和解密的过程中都使用了随机生成的 IV 和 auth tag,这可能会导致在解密过程中无法正确解密数据。

    你需要确保在加密和解密过程中使用的 IV 和 auth tag 是一致的。你可以尝试将加密过程中生成的 IV 和 auth tag 保存下来,然后在解密过程中使用同样的 IV 和 auth tag。

    另外,你的代码中在解密过程中使用了 base64 解码,但在加密过程中并没有对应的 base64 编码,这可能也会导致解密失败。你需要确保加密和解密过程中的编码和解码操作是一致的。

    以下是一个简化的示例,展示了如何在加密和解密过程中使用相同的 IV 和 auth tag:

    // 加密
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-gcm'));
    $tag = '';
    $ciphertext = openssl_encrypt($plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
    
    
    // 解密
    $decrypted = openssl_decrypt($ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
    
    2023-08-24
    有用
    回复 2
    • 刘洋
      刘洋
      2023-08-24
      这$iv和 authtag我这里一直都是不一致,我也不知道为什么,加密的时候传的,和解密后获得是不一样,但是还是可以解密得出来
      2023-08-24
      回复
    • 刘洋
      刘洋
      2023-08-24
      感觉换了你这个代码也是没用,情况一样
      2023-08-24
      回复
登录 后发表内容