node.jsgoogle-playrsain-app-billingserver-side-validation

Server side verification of Google Play in-app billing purchase signature failed


i'm currently integrating Google Play in-app billing to my androidgame project, i have a Node.js server set up and plan to send it the "originalJson" and "signature" value of the Google Play purchase response for server side verification.

then i put up a bit of test on my Node.js server, first here are the "originalJson" and "signature" value of one of my purchase(fetched from the client side):

   originalJson:{"orderId":"GPA.1312-8694-0319-25069","packageName":"com.shihu.sm.testin","productId":"com.shihu.sm.testin.diamond","purchaseTime":1452598011176,"purchaseState":0,"developerPayload":"{\"iabProductId\":\"com.shihu.sm.testin.diamond\",\"gOrderId\":\"2cb77de1a2a94db18b6df84f8037ea5b\",\"serverId\":\"6\",\"productId\":\"202\"}","purchaseToken":"bjoncdcebeclpklebmadidgb.AO-J1OyEbKLL0rhWQAc1hjdWyJPXHkAoHZTfZasqUuFWKWyAlnj-opiDLYILNRpnWgcblO8vV37fWf0kpeNMRZcgRT-fRxAO4P8VQPmU-TJakB-sCiRx8sUxL4nxnUBMnZdFWdpaIZDW5tP3Ck4aO57n1o66PwnjZw"}
   signature:JdfwMxprv7iMbI5YnVIWXLEAqiDhAQQva2IdfxtmhqBvLNU4Msi8sj31mnrVJfShxNmQI3zhlNUrCCaXdraFM0/y8O4PoZWYr+PFjCmlMovhG+ldeImEu7x52GLoQ7DsO8Yh4aLYmxemezFc1RjcSpq+l6Zzu9T6j3fHjLfQ060SEFapZITI/poxlFyvJX3bHhF9wGP54tL6pGjB/7fBEqTM1zHXUYeZyz+4akqV8oODlIWwMKhvN5tX/Zra9kh9hm0bnJT/1YWso3tLlT/WTK9nsP1l/lTnEXvgzq9QVSGbT/cpD7KSbR5N4i/NmPYAlCOvesW9OlRD05L8yytpBw==

then i wrote the following code to do the verification with "RSA-SHA1" algorithm and "base64" signature encoding:

    var crypto = require('crypto');

    console.log('start verification');

    var public_key = "-----BEGIN PUBLIC KEY-----" + "\r\n" + 
    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg+VmzvTvb856ur/J+PWC" + "\r\n" +
    "gFRhLYV/chAuWzUuqlIh5gnYz1RFOYymCWAKP3wguol8YSe/72zEqAvPutBU2XVj" + "\r\n" + 
    "zx3sHT+GUInbKjgZHzxw0viPh//OfaooEvEFMz9C6J8ABwpGNQUpACmyw12ZKshP" + "\r\n" +
    "HCJ6PZV+nsWry6PEZgnYCF7w5SDP4GY2tr3Q5D0iQwoALA40KYQfsKZ6pI5L8bDT" + "\r\n" +
    "2MLTFoemg/npeARy9HYkbonPatBhWjp2flzBRcyQx7DyQ7csLvPl5AGHRT4h5RBq" + "\r\n" + 
    "RlLj+DBgNDAdwvHGyfhbTz7fPsT6xn7qifxAN+2gQsemSVmhi15zECF/k5MtTiOF" + "\r\n" +
    "owIDAQAB" + "\r\n" + 
    "-----END PUBLIC KEY-----";

    verifier= crypto.createVerify("RSA-SHA1");
    originalJson = '{"orderId":"GPA.1312-8694-0319-25069","packageName":"com.shihu.sm.testin","productId":"com.shihu.sm.testin.diamond","purchaseTime":1452598011176,"purchaseState":0,"developerPayload":"{\"iabProductId\":\"com.shihu.sm.testin.diamond\",\"gOrderId\":\"2cb77de1a2a94db18b6df84f8037ea5b\",\"serverId\":\"6\",\"productId\":\"202\"}","purchaseToken":"bjoncdcebeclpklebmadidgb.AO-J1OyEbKLL0rhWQAc1hjdWyJPXHkAoHZTfZasqUuFWKWyAlnj-opiDLYILNRpnWgcblO8vV37fWf0kpeNMRZcgRT-fRxAO4P8VQPmU-TJakB-sCiRx8sUxL4nxnUBMnZdFWdpaIZDW5tP3Ck4aO57n1o66PwnjZw"}';
    signature = 'JdfwMxprv7iMbI5YnVIWXLEAqiDhAQQva2IdfxtmhqBvLNU4Msi8sj31mnrVJfShxNmQI3zhlNUrCCaXdraFM0/y8O4PoZWYr+PFjCmlMovhG+ldeImEu7x52GLoQ7DsO8Yh4aLYmxemezFc1RjcSpq+l6Zzu9T6j3fHjLfQ060SEFapZITI/poxlFyvJX3bHhF9wGP54tL6pGjB/7fBEqTM1zHXUYeZyz+4akqV8oODlIWwMKhvN5tX/Zra9kh9hm0bnJT/1YWso3tLlT/WTK9nsP1l/lTnEXvgzq9QVSGbT/cpD7KSbR5N4i/NmPYAlCOvesW9OlRD05L8yytpBw=='

    verifier.update(originalJson);
    if(verifier.verify(public_key, signature, "base64"))
        console.log('verification succeeded');
    else
        console.log("verification failed");

the key string in the middle is the base64 encoded public key from Google Console split by '\r\n' with every 64 characters. at the beginning i didn't split it into chunks of 64 characters and kept failing with error saying can't generate the pub key object, it was later i followed some examples on the internet and got passed that, but till now, i haven't got a successful verification result yet.

i have referenced some more examples, and i think the 'RSA-SHA1' and 'base64' settings for the verification are the correct ones, so what am i still missing or doing wrong?

thanks


Solution

  • It seems that your originalJson string is missing some necessary escaping.

    I've managed to verify the signature with the escaping added back in:

    var originalJson = '{"orderId":"GPA.1312-8694-0319-25069","packageName":"com.shihu.sm.testin","productId":"com.shihu.sm.testin.diamond","purchaseTime":1452598011176,"purchaseState":0,"developerPayload":"{\\"iabProductId\\":\\"com.shihu.sm.testin.diamond\\",\\"gOrderId\\":\\"2cb77de1a2a94db18b6df84f8037ea5b\\",\\"serverId\\":\\"6\\",\\"productId\\":\\"202\\"}","purchaseToken":"bjoncdcebeclpklebmadidgb.AO-J1OyEbKLL0rhWQAc1hjdWyJPXHkAoHZTfZasqUuFWKWyAlnj-opiDLYILNRpnWgcblO8vV37fWf0kpeNMRZcgRT-fRxAO4P8VQPmU-TJakB-sCiRx8sUxL4nxnUBMnZdFWdpaIZDW5tP3Ck4aO57n1o66PwnjZw"}';
    

    Pay attention to the \\'s. The string is different otherwise.