'How to verify unity's GooglePlay in app billing signature?

from unity reference, to verify an in-app purchase(GooglePlay), we should get Payload from Receipt, then verify Payload.json(INAPP_PURCHASE_DATA) and Payload.signature(INAPP_DATA_SIGNATURE) like this:

const (
    cGooglePubKey = "MIIBIjANBgkqhki...............AQAB"
)

var (
    data = `{\"orderId\":\"GPA.A-B-C-D\",\"packageName\":\"com.x.y\",\"productId\":\"pdt1\",\"purchaseTime\":1653297088926,\"purchaseState\":0,\"purchaseToken\":\"xxxxx\",\"acknowledged\":false}`
    sign = "R6U/cmXT...RfOg=="
)

func main() {
    if ok, err := validateGooglePay(data, sign, cGooglePubKey); ok {
        println("YES!!")
    } else {
        println(err.Error())
    }
}

func validateGooglePay(purchaseData string, signature string, publicKey string) (bool, error) {
    decodePublic, err := base64.StdEncoding.DecodeString(publicKey)
    if err != nil {
        return false, err
    }
    pubInterface, err := x509.ParsePKIXPublicKey(decodePublic)
    if err != nil {
        return false, err
    }
    pubKey, _ := pubInterface.(*rsa.PublicKey)
    decodeSign, err := base64.StdEncoding.DecodeString(signature)
    if err != nil {
        return false, err
    }

    sh1 := sha1.New()
    sh1.Write([]byte(purchaseData))
    hashData := sh1.Sum(nil)
    result := rsa.VerifyPKCS1v15(pubKey, crypto.SHA1, hashData, decodeSign)
    if result != nil {
        return false, result
    }
    return true, nil
}

But I failed with "crypto/rsa: verification error"! And WHY?

I even use PHP to test, still failed:

<?php
if (checkGpBilling() !== true) {
 print("FAILED\n");   
}

function checkGpBilling() {
    $inappPurchaseData = '{\"orderId\":\"GPA.A-B-C-D\",\"packageName\":\"com.x.y\",\"productId\":\"pdt2\",\"purchaseTime\":1653297088926,\"purchaseState\":0,\"purchaseToken\":\"hmj...f3A\",\"acknowledged\":false}';
    $inappDataSignature = 'R6U/cmX...RfOg==';
    $googlePublicKey = 'MIIBIjANBgkqhki...AQAB';
 
    $publicKey = "-----BEGIN PUBLIC KEY-----". PHP_EOL .
                                                     chunk_split($googlePublicKey, 64, PHP_EOL) . 
                                                     "-----END PUBLIC KEY-----";
 
    $publicKeyHandle =  openssl_get_publickey($publicKey);
    $result = openssl_verify($inappPurchaseData, base64_decode($inappDataSignature), $publicKeyHandle, OPENSSL_ALGO_SHA1);
    if (1 !== $result) {
            print($result);
            return false;
    }
 
    return true;
}

Can anyone correct me if i was wrong, or please tell me the right way/code? thanks very much!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source