签名验证,Android应用程序结算在以前工作后失败

时间:2013-01-28 08:26:29

标签: android in-app-billing

背景:

我们有一款Android应用,目前通过Google Play发售。要使应用程序正常运行,用户必须通过In-App Billing购买“令牌”。 “令牌”是消耗品,例如使用一次并完成。为了验证令牌,我们将购买数据发送到使用标准Java RSA安全代码的服务器,以验证从Play商店返回的信息是否有效。 (以下代码)。 我们在发布应用程序之前进行了大量测试,即使应用程序在商店中,我们也进行了一些测试。每次从Google返回的数据都会通过验证。然后在12月初,签名验证开始失败。我们没有更改商店中的代码或应用程序,并且服务器上的验证代码保持不变。

我调试了代码,并运行了从Play商店返回的收据数据和签名数据,现在确实无法验证。当它工作正常时,我无法解释发生了什么变化,或者验证开始失败的原因。

问题:

之前是否有人遇到此问题,在未更改的应用中签名验证失败?关于从哪里开始寻找尝试找出可能出现问题的地方的任何提示?

更多信息

我唯一能想到改变的是Google发布了应用内结算API v3,但这不应该影响我们使用的V2。

为了帮助开发,我们使用net.robotmedia.billing库来处理IAB。

以下是从Play商店

返回的数据的服务器验证码

其中encodePublicKey =>来自Play商店的公钥

signedData => base64编码的receiptData作为Play商店购买的回报

signature =>从Play商店返回的签名

public class Security {

    public final static Logger logger = Logger.getLogger(Security.class.getName());

    private static final String KEY_FACTORY_ALGORITHM = "RSA";
    private 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
     */
    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.error("Invalid key specification.", e);
            throw new IllegalArgumentException(e);
        }
        catch (Base64DecoderException e) {
            logger.error("Base64 decoding failed.", e);
            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());
            byte[] decodedSig = Base64.decode(signature);
            if (!sig.verify(decodedSig)) {
                logger.error("Signature verification failed.");
                return false;
            }
            return true;
        }
        catch (NoSuchAlgorithmException e) {
            logger.error("NoSuchAlgorithmException.");
        }
        catch (InvalidKeyException e) {
            logger.error("Invalid key specification.");
        }
        catch (SignatureException e) {
            logger.error("Signature exception.");
        }
        catch (Base64DecoderException e) {
            logger.error("Base64 decoding failed.");
        }
        return false;
    }

}

2 个答案:

答案 0 :(得分:1)

对我来说可能文件编码是问题, 更改eclipse工作区后,它再次使用mac文件格式。

将密钥再次更改为 UTF-8 复制并粘贴 密钥再次进入项目,

现在一切正常:/ / 浪费时间:/

答案 1 :(得分:0)

只是一个更新。我从来没有理清为什么它停止了验证失败。我们认为这可能是Google Play服务器和我们的公钥的问题。

无论如何,解决方案就是实施应用内结算v3 Api(比旧版BTW更好)并且它再次开始工作。

所以,这不是一个明确的答案,而是一个解决方案。