在Google app Engine上用Python验证android应用内购买消息的签名

在Google app Engine上用Python验证android应用内购买消息的签名,python,android,google-app-engine,in-app-purchase,Python,Android,Google App Engine,In App Purchase,android开发者网站上的示例应用程序使用java代码验证购买json。有没有人有幸找到了用python验证购买的方法。特别是在GAE 以下是android应用内计费的相关摘录。这就是需要转换为python的东西,使用python,Google将其重新编写为完全python,并且是AppEngine上唯一可用的安全库。希望谷歌对我使用下面的摘录很酷 private static final String KEY_FACTORY_ALGORITHM = "RSA"; private static

android开发者网站上的示例应用程序使用java代码验证购买json。有没有人有幸找到了用python验证购买的方法。特别是在GAE

以下是android应用内计费的相关摘录。这就是需要转换为python的东西,使用python,Google将其重新编写为完全python,并且是AppEngine上唯一可用的安全库。希望谷歌对我使用下面的摘录很酷

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;
}
我是这样做的:

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存储密钥

对于更愿意使用m2crypto的人,
validate\u 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中发现您的base64编码公钥是一个X.509 subjectPublicKeyInfo序列,签名方案是RSASSA-PKCS1-v1_5,而不是RSASSA-PSS。如果您已经安装了,它实际上非常简单:

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年,下面介绍如何使用
加密技术

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

我不打算将此作为一个答案发布,因为我不知道这是否正是你想要的,但试试看,它展示了如何编写一个用JSON响应的GAE应用程序,你可以修改它来提供你的验证,我想我必须在
validate\u purchase(publicKey,signedData,signature)中添加以下行
使其工作的函数:
signedData=signedData.encode(“utf8”)
谢谢你,你让我度过了美好的一天!您还可以将Google许可证转换为有效的公钥,如:
openssl enc-base64-d-in publickey.base64-a | openssl rsa-inform DER-pubin>publickey.pem