onepf / OpenIAB

Open In-App Billing for Google Play, SlideMe, Amazon Store, Nokia Store, Samsung Apps, Yandex.Store, Appland, Aptoide, AppMall and Fortumo.
http://onepf.org/openiab/
Apache License 2.0
473 stars 172 forks source link

OpenIAB Purchase Server Verify Issue #509

Open hedoudou opened 8 years ago

hedoudou commented 8 years ago

We are building an App which using OpenIAB to interact with Yandex.Store. On the android client side, we can buy the In-App items successfully, The problem is that always failed to verify the purchase on server side(We have a Spring MVC based web server to verify the purchase), but it can verify success on Android code. Finally i figured out that the root cause is KeyFactory.java and Signature.java which in JDK1.8 and android.jar has different implementation. But i still have no idea how to fix it on Web Server side, any help would be appreciate.

Following are purchase verification code snippet:,
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {

    if (StringUtils.isEmpty(signedData) || StringUtils.isEmpty(base64PublicKey) ||

    StringUtils.isEmpty(signature)) {

    logger.info("Purchase verification failed: missing data.");

        return false;

    }

    PublicKey key = Security.generatePublicKey(base64PublicKey);

    return Security.verify(key, signedData, signature);

}

/**

 * 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

 */

public static PublicKey generatePublicKey(String encodedPublicKey) {

    try {

        byte[] decodedKey = Base64.decode(encodedPublicKey);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);

        return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));

    } catch (NoSuchAlgorithmException e) {

        throw new RuntimeException(e);

    } catch (InvalidKeySpecException e) {

    logger.info("Invalid key specification.");

        throw new IllegalArgumentException(e);

    } catch (Base64DecoderException e) {

    logger.info("Base64 decoding failed.");

        throw new IllegalArgumentException(e);

    }

}

/**

 * Verifies that the signature from the server matches the computed

 * signature on the data.  Returns true if the data is correctly signed.

 *

 * @param publicKey public key associated with the developer account

 * @param signedData signed data from server

 * @param signature server signature

 * @return true if the data and signature match

 */

public static boolean verify(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))) {

        logger.info("Signature verification failed.");

            return false;

        }

        return true;

    } catch (NoSuchAlgorithmException e) {

    logger.info("NoSuchAlgorithmException.");

    } catch (InvalidKeyException e) {

    logger.info("Invalid key specification.");

    } catch (SignatureException e) {

    logger.info("Signature exception.");

    } catch (Base64DecoderException e) {

    logger.info("Base64 decoding failed.");

    }

    return false;

}