Last active
August 29, 2022 12:34
-
-
Save LiEnby/d31334bd3d169b41918ffacda3b0ac1d to your computer and use it in GitHub Desktop.
Validate minecraft entitlements
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# --=== Created by Li ===-- | |
# Minecraft Entitlement Verifier | |
# Requires decrypted .ent (pre-1.19) or from PlayFab Api | |
# (i was too lazy to implement ent decryption) | |
# | |
# This script mathematically verifies if a given entitlement file was generated by Mojang or not. | |
# | |
# Usage: | |
# type plaintext.ent | py ent_validate.py (Windows) | |
# cat plaintext.ent | python3 ent_validate.py (Linux) | |
# | |
# required pip packages: | |
# | |
# pip3 install cryptography | |
# pip3 install requests | |
# pip3 install hashlib | |
# Public Domain | |
import cryptography | |
import hashlib | |
import requests | |
import os | |
import binascii | |
import json | |
import base64 | |
import sys | |
from cryptography import x509 | |
from cryptography.hazmat.primitives.asymmetric import padding | |
from cryptography.hazmat.primitives import hashes | |
ISSUE_CERT = "ReceiptIssuerCertificate.pem" | |
def checkItem(itm): | |
receipt = itm['Receipt'] | |
valid = verifyReceipt(receipt) | |
return valid | |
def verifyEnt(entitlements): | |
ent = json.loads(entitlements) | |
for itm in ent["Items"]: | |
if not checkItem(itm): | |
return False | |
for itm in ent["Subscriptions"]: | |
if not checkItem(itm): | |
return False | |
if not verifyReceipt(ent["Receipt"]): | |
return False | |
return True | |
def getReceiptIssuerCertificate(): | |
if not os.path.exists(ISSUE_CERT): | |
pem = requests.get("https://20ca2.playfabapi.com/inventory/GetReceiptIssuerCertificateAsPem").json()["data"]["PemCert"].encode("UTF-8") | |
open(ISSUE_CERT, "wb").write(pem) | |
return pem | |
else: | |
pem = open(ISSUE_CERT, "rb").read() | |
return pem | |
def hashJWT(jwt): | |
parts = jwt.split(".") | |
sha256 = hashlib.sha256() | |
sha256.update(parts[0].encode("UTF-8")+b"."+parts[1].encode("UTF-8")) | |
return sha256.hexdigest() | |
def b64url(data): | |
data += "=" * (len(data) % 4) | |
return base64.urlsafe_b64decode(data) | |
def verifyReceipt(receipt): | |
expectedHash = hashJWT(receipt) | |
cert = x509.load_pem_x509_certificate(getReceiptIssuerCertificate()) | |
pubkey = cert.public_key() | |
signature = b64url(receipt.split(".")[2]) | |
gotHash = binascii.hexlify(pubkey.recover_data_from_signature(signature, padding.PKCS1v15(), hashes.SHA256)).decode("UTF-8") | |
if expectedHash == gotHash: | |
return True | |
else: | |
return False | |
if __name__ == "__main__": | |
v = verifyEnt(input()) | |
if v: | |
print("Ent Verify Success") | |
else: | |
print("Ent Verify Fail") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment