PHP server side IAB verification openssl_verify al

2019-07-16 13:11发布

问题:

I'm using the following function (server side php) to verify a IAB v3 transaction:

I'm passing from the android app:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

                         String signed_data=data.getStringExtra(IabHelper.RESPONSE_INAPP_PURCHASE_DATA);
                         String signature=data.getStringExtra(IabHelper.RESPONSE_INAPP_SIGNATURE);

I have a feeling it may have something to do with the signature I'm passing. I'm using the following Android method to encode it, because without encoding I get an error:

public String URLsafe(String text){
        try {
            return URLEncoder.encode(text, "utf-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();;
        }
        return null;
    }

I'm passing the url

http://www.example.com/handlepayment.php?signature=....&data=....


public String getXmlFromUrl(String url) {

        String xml = null;

        try {
            // defaultHttpClient
            DefaultHttpClient httpClient = new   MyHttpClient_ALKS(myContext.getApplicationContext());
            HttpPost httpPost = new HttpPost(url);

            HttpResponse httpResponse = httpClient.execute(httpPost);

            HttpEntity httpEntity = httpResponse.getEntity();
            xml = EntityUtils.toString(httpEntity);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
         return xml;
    }

to the server:

function verify_play($signed_data, $signature) 
{
  global $public_key_base64;
  $pkey =  "-----BEGIN PUBLIC KEY-----\n".
    chunk_split($public_key_base64, 64,"\n").
    '-----END PUBLIC KEY-----';   
  //using PHP to create an RSA key
  $pkey = openssl_get_publickey($pkey);
  //$signature should be in binary format, but it comes as BASE64. 
  //So, I'll convert it.
  $signature = base64_decode($signature);   
  //using PHP's native support to verify the signature
  $result = openssl_verify(
      $signed_data,
      $signature,
      $pkey,
      OPENSSL_ALGO_SHA1);

  if (0 === $result) 
  {
    return false;
  }
  else if (1 !== $result)
  {
    return false;
  }
  else 
  {
    return true;
  }
} ;

It always seem to return false ($result=0), anybody any idea why? How can I pass the signature un-encoded, or which encoding should I use?

回答1:

In my experience openssl_get_publickey() only creates public key resources when you have a public key in an X.509 cert.

My recommendation would be to use phpseclib, a pure PHP RSA implementation. eg.

function verify_play($signed_data, $signature) 
{
  global $public_key_base64;
  $rsa = new Crypt_RSA();
  $rsa->loadKey($public_key_base64);
  $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
  $signature = base64_decode($signature);   
  return $rsa->verify($signed_data, $signature);
}