title: How to validate Google receipt validation locally with old Order ID format?
body: <p>I want to validate Google receipt validation but since I don't have client key, <strong>I cannot use Google API</strong>:  <a href="https://developers.google.com/android-publisher/archive/v1_1/inapppurchases/get" rel="noreferrer">https://developers.google.com/android-publisher/archive/v1_1/inapppurchases/get</a></p>
  
  <p>So I do local validation by using <code>public key</code>, <code>signedData</code> and <code>signature</code>.</p>
  
  <p>Everything works fine since I have new <code>orderId</code> with format:</p>
  
  <p><code>GPA.XXXX-XXXX-XXXX-XXXXX</code></p>
  
  <p>However this code doesn't work for old pattern <code>orderId</code> that looks like:</p>
  
  <pre><code>4582257046313445026.7467948335710411
  </code></pre>
  
  <p>I get Exception:</p>
  
  <blockquote>
    <p>Signature exception java.security.SignatureException: Signature length not correct: got 294 but was expecting 256</p>
  </blockquote>
  
  <p>So I succeeded to generate <code>PublicKey</code> bu fails on <code>verify</code>:</p>
  
  <pre><code>sig.verify(Base64.decode(signature, Base64.DEFAULT) // &lt;- java.security.SignatureException
  </code></pre>
  
  <p>I know that <code>RSA</code> signature should be 256, in my case I got 294</p>
  
  <p>Ref: <a href="https://stackoverflow.com/questions/31602234/google-play-order-id-updated-to-new-format">Google Play Order ID updated to new format</a></p>
  
  <h3>Code example</h3>
  
  <pre><code>String base64PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3dkBTr2pD2YSqSK2ewlEWwH9Llu0iA4PkwgVOyNRxOsHfrOlqi0Cm51qdNS0aqh/SMZkuQTAroqH3pAr9gVFOiejKRw+ymTaL5wB9+5n1mAbdeO2tv2FDsbawDvp7u6fIBejYt7Dtmih+kcu707fEO58HZWqgzx9qSHmrkMZr6yvHCtAhdBLwSBBjyhPHy7RAwKA+PE+HYVV2UNb5urqIZ9eI1dAv3RHX/xxHVHRJcjnTyMAqBmfFM+o31tp8/1CxGIazVN6HpVk8Qi2uqSS5HdKUu6VnIK8VuAHQbXQn4bG6GXx5Tp0SX1fKrejo7hupNUCgOlqsYHFYxsRkEOi0QIDAQAB";
  String signedData = "{\"orderId\":\"GPA.3353-8027-5082-45637\",\"packageName\":\"com.mycompany.testapp\",\"productId\":\"weekly\",\"purchaseTime\":1503578932746,\"purchaseState\":0,\"developerPayload\":\"1502364785372-5918650324956818356\",\"purchaseToken\":\"bfljoelddlibhbibhnbnflej.AO-J1Oz8pvdqCmzz04OBmegRVKEG1stj4su5HH4uc-gzsz_vlhcz7iB_NUZVBNXp3RlTGyIGnsIgOe6bqvqfUIbPC9_CrCngL0EkZp-SBwaRzfn-EgJ32yQ\",\"autoRenewing\":true}";
  String signature = "TyVJfHg8OAoW7W4wuJtS4dM//zmyECiNzWa8wuVrXyDOCPirHqxjpNthq23lmAZlxbTXyMNwedMQPr9R8NJtp3VTzGuNlLYBSOERVehmgstXiiwWDBvTNzgWbwimZmFaIiCExMQiPvbXHoWQh2rClFeAd4FfdC15pNf3NqfOGhUAEmieeb572umOo4YoF0l0421pY/JWYXa+2dtO6pcnSHF6gidRDXR66s/enRZUvkB4x9CEHdA862LDKbwOG4Aihh03IRLjD+m/5WNW+w05Q8bNNA6sCzFGVD+qa3IDiSqkiISCpd3UnufePxf3+O2doWjg2mXC5agEDMnNXvhfrw==";
  
  
  boolean result = DefaultSignatureValidator.validate(base64PublicKey, signedData, signature); 
  </code></pre>
  
  <hr>
  
  <p><em>DefaultSignatureValidator.class</em>:</p>
  
  <pre><code>public class DefaultSignatureValidator {
  
          protected static final String KEY_FACTORY_ALGORITHM = "RSA";
          protected static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
  
          /**
           * Generates a PublicKey instance from a string containing the
           * Base64-encoded public key.
           * 
           * @param encodedPublicKey
           *            Base64-encoded public key
           * @throws IllegalArgumentException
           *             if encodedPublicKey is invalid
           */
          protected static PublicKey generatePublicKey(String encodedPublicKey) {
              try {
                  byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT);
                  KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
                  return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
              } catch (NoSuchAlgorithmException e) {
                  throw new RuntimeException(e);
              } catch (InvalidKeySpecException e) {
                  System.out.println("Invalid key specification.");
                  throw new IllegalArgumentException(e);
              } catch (Exception e) {
                  System.out.println("Base64 decoding failed.");
                  throw new IllegalArgumentException(e);
              }
          }
  
          protected static boolean validate(PublicKey publicKey, String signedData, String signature) {
              Signature sig;
              try {
                  sig = Signature.getInstance(SIGNATURE_ALGORITHM);
                  sig.initVerify(publicKey);
                  sig.update(signedData.getBytes());
                  if (!sig.verify(Base64.decode(signature, Base64.DEFAULT))) {
                      System.out.println("Signature verification failed.");
                      return false;
                  }
                  return true;
              } catch (NoSuchAlgorithmException e) {
                  System.out.println("NoSuchAlgorithmException" + e);
              } catch (InvalidKeyException e) {
                  System.out.println("Invalid key specification" + e);
              } catch (SignatureException e) {
                  System.out.println("Signature exception" + e);
              } catch (Exception e) {
                  System.out.println("Base64 decoding failed" + e);
              }
              return false;
          }
  
          public static boolean validate(String base64PublicKey, String signedData, String signature) {
  
              PublicKey key = DefaultSignatureValidator.generatePublicKey(base64PublicKey);
              return DefaultSignatureValidator.validate(key, signedData, signature);
          }
  }
  </code></pre>
  
  <p>Any ideas how to validate it?</p>
  
  <p>If you have solution, no matter in what language Clojure, Skala, Ruby, Java ..... </p>