3

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?

Diego
  • 4,011
  • 10
  • 50
  • 76

1 Answers1

2

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);
}
neubert
  • 15,947
  • 24
  • 120
  • 212
  • Thanks, when I test it with a real transaction it gives me this error: function _rsassa_pkcs1_v1_5_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { user_error('Invalid signature'); return false; } – Diego Dec 04 '13 at 17:48
  • Can you post the public key and the signature? Maybe the signed data too. All of that will enable me to better diagnose the issue. Thanks. – neubert Dec 05 '13 at 14:31