使用应用内结算时,您应通过使用Google Play商店中的base64编码公钥检查INAPP_PURCHASE_DATA是否已使用INAPP_DATA_SIGNATURE进行签名来验证购买数据。
请参阅INAPP_PURCHASE_DATA和INAPP_DATA_SIGNATURE here的说明。
您可以使用Security class来验证购买:
public class Security {
private static final String TAG = "IABUtil/Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* Verifies that the data was signed with the given signature, and returns
* the verified purchase. The data is in JSON format and signed
* with a private key. The data also contains the {@link PurchaseState}
* and product ID of the purchase.
* @param base64PublicKey the base64-encoded public key to use for verifying.
* @param signedData the signed JSON string (signed, not encrypted)
* @param signature the signature for the data, signed with the private key
*/
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) {
Log.e(TAG, "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, 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) {
Log.e(TAG, "Invalid key specification.");
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) {
byte[] signatureBytes;
try {
signatureBytes = Base64.decode(signature, Base64.DEFAULT);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Base64 decoding failed.");
return false;
}
try {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (!sig.verify(signatureBytes)) {
Log.e(TAG, "Signature verification failed.");
return false;
}
return true;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "NoSuchAlgorithmException.");
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key specification.");
} catch (SignatureException e) {
Log.e(TAG, "Signature exception.");
}
return false;
}
}
您必须调用verifyPurchase
并从Google Play传递购买数据,给定签名和base64PublicKey公钥。我可以在我的应用中使用wrapper implementation购买流程
如果您查看IabHelper实现,它们会在构造函数中传递用于验证的公钥。 ctor的文档说:
* @param base64PublicKey Your application's public key, encoded in base64.
* This is used for verification of purchase signatures. You can find your app's base64-encoded
* public key in your application's page on Google Play Developer Console. Note that this
* is NOT your "developer public key".
*/
我猜他们的意思是许可& amp;中的Base64编码的RSA公钥。 Google Play中的应用内结算部分:
也许我对密码学知之甚少,但是如何使用Google Play的公钥来检查加密,这可能是用我的“开发人员私钥”进行的(请参阅第一个链接中的说明)。他们是否意味着我“用于签署应用程序的私钥”?我不这么认为,因为他们无法知道我的(本地)私钥(我用来签署我的应用)以及它与Google Play的这个公钥有什么关系,所以他们对“开发者的私钥”有何意义”。
所以我的问题是:
我是否理解公钥是关键所在 许可&应用内结算?
我是否还需要add licensing to my app来获取此信息 验证工作或应该“开箱即用”,我也可以 省略这一步?
谷歌用于签署的“开发者私钥”是什么? 购买数据,我在哪里看到它? (我需要运行一些单元测试 在我的服务器上检查我的实现,我想加密 INAPP_PURCHASE_DATA也可以获得INAPP_DATA_SIGNATURE 能够获得有效的安全检查,如果我用给定的验证它 公钥。
[UPDATE] 即可。显然,私钥是隐藏的:
Google Play控制台会向登录Play控制台的任何开发者公开许可公钥,但会将所有用户的私钥隐藏在安全位置。
请参阅:https://developer.android.com/google/play/licensing/adding-licensing.html
答案 0 :(得分:2)
有两种类型的签名不对称&对称:
Asymm使用一对密钥,私有密钥和公共密钥,密钥在它们之间具有数学关系,用私钥签名的一个数据块可以用公共密钥验证。私钥永远不会发布,但公众是。
然后Google为您的应用内结算创建了一对密钥...但您只需要知道公众进行验证。 没有私钥,任何机构都不会生成有效签名。
相反,Symm在两侧使用相同的密钥,这会导致共享密钥的问题与被嗅探的风险,但它的优势在于比asymm更快。
<强>更新强>
我是否还需要向我的应用添加许可才能获得此验证 工作或应该“开箱即用”,我可以省略这一步吗?
取决于,如果您想知道该应用是否已从官方Google Play商店安装,那么您需要验证许可,如果您的应用是付费应用,则会更好地适用,相反,如果您的应用是免费的,但它有 - 应用程序产品重要的是要知道他们是否合法购买了该项目。
对我而言,在外部服务器验证购买更为重要,那里有一个很好的例子https://stackoverflow.com/a/48645216/7690376