2011-03-26 2 views
14

안드로이드 개발자 사이트의 샘플 애플리케이션은 java 코드를 사용하여 json의 유효성을 검사합니다. 아무도 python으로 구매를 검증하는 방법을 찾지 못했다. 특히 GAE에서?Google App Engine의 Python에서 안드로이드 인앱 구매 메시지의 서명 확인

다음은 Android 인앱 결제 example program의 발췌 내용입니다. 이것은 PyCrypto을 사용하여 파이썬으로 변환해야하며, 이는 Google이 완전히 파이썬으로 작성했으며, 앱 엔진에서 사용할 수있는 유일한 보안 lib입니다. 바라건대 Google은 다음 발췌문을 사용하여 나에게 멋지다.

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; 
} 
+0

이 나는대로이를 게시하지 않을거야 당신이 정확히 무엇을 찾고 있는지를 알 수 없기 때문에 답변을 해보지 만,이 [link - Google Code] (http://code.google.com/appengine/articles/rpc.html)를 사용해보십시오. 내가 생각하는 유효성을 제공하기 위해 수정할 수있는 JSON으로 응답 할 GAE 앱 – Timbermar

답변

15

여기에 어떻게 내가 해냈어 :

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이 64 기수가 개발자 콘솔에서 그것을 얻을 구글은 한 줄에 저장 키를 재생 인코딩 된 것으로 가정합니다. 에

오히려 m2crypto를 사용하는 사람들을 위해

, validate_purchase() 변경 것이다 : 나는 마침내 base64로 구글 플레이에서 공개 키를 인코딩 된 것으로 파악

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 
+0

'validate_purchase (publicKey, signedData, signature) '함수에 다음 행을 추가해야 작동 가능합니다. 'signedData = signedData.encode ("utf8")' – Saqib

+0

감사합니다, 당신은 내 하루를 보냈습니다! 다음과 같이 유효한 공개 키로 Google 라이선스를 변형 할 수도 있습니다.'openssl enc -base64 -d -in publickey.base64 -A | openssl rsa -inform DER -pubin> publickey.pem' – Moritz

7

인 X.509 SubjectPublicKeyInfo로 DER의 SEQUENCE, 그 서명 방식 RSASSA-PKCS1-v1_5이며 RSASSA-PSS는 아닙니다. 여기, 우리는 2016 년 걸 이제

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) 
+0

이 답변은 주요 형식을 혼동하지 않고 잘 작동합니다. –

1

cryptography와 그 방법은 다음과 같습니다 : 당신이 PyCrypto가 설치되어있는 경우, 그것은 아주 쉽게 사실이다

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