在Google App Engine上使用PythonvalidationAndroid应用内购买消息的签名

Android开发人员网站上的示例应用程序使用Java代码validation购买JSON。 有没有人有任何运气如何validation在Python购买。 特别是在GAE?

以下是Android应用内结算示例程序的相关摘录。 这就是需要使用PyCrypto转换为python, pyCrypto被Google重新编写为完全Python,并且是应用程序引擎上唯一可用的安全库。 希望谷歌使用下面的摘录很酷。

private static final String KEY_FACTORY_ALGORITHM = "RSA"; private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; String base64EncodedPublicKey = "your public key here"; PublicKey key = Security.generatePublicKey(base64EncodedPublicKey); verified = Security.verify(key, signedData, signature); 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 ... } } public static boolean verify(PublicKey publicKey, String signedData, String signature) { if (Consts.DEBUG) { Log.i(TAG, "signature: " + signature); } Signature sig; try { sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initVerify(publicKey); sig.update(signedData.getBytes()); if (!sig.verify(Base64.decode(signature))) { Log.e(TAG, "Signature verification failed."); return false; } return true; } catch ... } return false; } 

Related of "在Google App Engine上使用PythonvalidationAndroid应用内购买消息的签名"

我是这么做的:

 from Crypto.Hash import SHA from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 from base64 import b64decode def chunks(s, n): for start in range(0, len(s), n): yield s[start:start+n] def pem_format(key): return '\n'.join([ '-----BEGIN PUBLIC KEY-----', '\n'.join(chunks(key, 64)), '-----END PUBLIC KEY-----' ]) def validate_purchase(publicKey, signedData, signature): key = RSA.importKey(pem_format(publicKey)) verifier = PKCS1_v1_5.new(key) data = SHA.new(signedData) sig = b64decode(signature) return verifier.verify(data, sig) 

这假定publicKey是您从开发者控制台获取的base64编码的Google Play Store密钥。

对于使用m2crypto的人来说, validate_purchase()会变成:

 from M2Crypto import RSA, BIO, EVP from base64 import b64decode # pem_format() as above def validate_purchase(publicKey, signedData, signature): bio = BIO.MemoryBuffer(pem_format(publicKey)) rsa = RSA.load_pub_key_bio(bio) key = EVP.PKey() key.assign_rsa(rsa) key.verify_init() key.verify_update(signedData) return key.verify_final(b64decode(signature)) == 1 

我终于明白,你的Google Play公钥是一个X.509 subjectPublicKeyInfo DER SEQUENCE,签名scheme是RSASSA-PKCS1-v1_5,而不是RSASSA-PSS。 如果你安装了PyCrypto ,实际上很简单:

 import base64 from Crypto.Hash import SHA from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 # Your base64 encoded public key from Google Play. _PUBLIC_KEY_BASE64 = "YOUR_BASE64_PUBLIC_KEY_HERE" # Key from Google Play is a X.509 subjectPublicKeyInfo DER SEQUENCE. _PUBLIC_KEY = RSA.importKey(base64.standard_b64decode(_PUBLIC_KEY_BASE64)) def verify(signed_data, signature_base64): """Returns whether the given data was signed with the private key.""" h = SHA.new() h.update(signed_data) # Scheme is RSASSA-PKCS1-v1_5. verifier = PKCS1_v1_5.new(_PUBLIC_KEY) # The signature is base64 encoded. signature = base64.standard_b64decode(signature_base64) return verifier.verify(h, signature) 

现在我们已经在2016年了,下面就是如何用cryptography来做到这一点:

 import base64 import binascii from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding class RSAwithSHA1: def __init__(self, public_key): # the public key google gives you is in DER encoding # let cryptography handle it for you self.public_key = serialization.load_der_public_key( base64.b64decode(public_key), backend=default_backend() ) def verify(self, data, signature): """ :param str data: purchase data :param str signature: data signature :return: True signature verification passes or False otherwise """ # note the signature is base64 encoded signature = base64.b64decode(signature.encode()) # as per https://developer.android.com/google/play/billing/billing_reference.html # the signature uses "the RSASSA-PKCS1-v1_5 scheme" verifier = self.public_key.verifier( signature, padding.PKCS1v15(), hashes.SHA1(), ) verifier.update(data.encode()) try: verifier.verify() except InvalidSignature: return False else: return True