mirror of
https://github.com/drmext/MonkeyBusiness.git
synced 2025-02-13 09:02:37 +01:00
Add card conversion util for DDR login screen
This commit is contained in:
parent
e8540eac52
commit
b41f622cac
@ -2,6 +2,8 @@ from fastapi import APIRouter, Request, Response
|
|||||||
|
|
||||||
from core_common import core_process_request, core_prepare_response, E
|
from core_common import core_process_request, core_prepare_response, E
|
||||||
|
|
||||||
|
import utils.card as conv
|
||||||
|
|
||||||
router = APIRouter(prefix="/local2", tags=["local2"])
|
router = APIRouter(prefix="/local2", tags=["local2"])
|
||||||
router.model_whitelist = ["MDX"]
|
router.model_whitelist = ["MDX"]
|
||||||
|
|
||||||
@ -9,10 +11,11 @@ router.model_whitelist = ["MDX"]
|
|||||||
@router.post('/{gameinfo}/system/convcardnumber')
|
@router.post('/{gameinfo}/system/convcardnumber')
|
||||||
async def system_convcardnumber(request: Request):
|
async def system_convcardnumber(request: Request):
|
||||||
request_info = await core_process_request(request)
|
request_info = await core_process_request(request)
|
||||||
|
cid = request_info['root'][0].find('data/card_id').text
|
||||||
|
|
||||||
response = E.response(
|
response = E.response(
|
||||||
E.system(
|
E.system(
|
||||||
E.data(E.card_number('FFFFFFFFFFFFFFFF', __type="str")),
|
E.data(E.card_number(conv.to_konami_id(cid), __type="str")),
|
||||||
E.result(0, __type="s32"),
|
E.result(0, __type="s32"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,8 @@ from fastapi import APIRouter, Request, Response
|
|||||||
|
|
||||||
from core_common import core_process_request, core_prepare_response, E
|
from core_common import core_process_request, core_prepare_response, E
|
||||||
|
|
||||||
|
import utils.card as conv
|
||||||
|
|
||||||
router = APIRouter(prefix="/local2", tags=["local2"])
|
router = APIRouter(prefix="/local2", tags=["local2"])
|
||||||
router.model_whitelist = ["MDX"]
|
router.model_whitelist = ["MDX"]
|
||||||
|
|
||||||
@ -9,10 +11,11 @@ router.model_whitelist = ["MDX"]
|
|||||||
@router.post('/{gameinfo}/system_2/convcardnumber')
|
@router.post('/{gameinfo}/system_2/convcardnumber')
|
||||||
async def system_2_convcardnumber(request: Request):
|
async def system_2_convcardnumber(request: Request):
|
||||||
request_info = await core_process_request(request)
|
request_info = await core_process_request(request)
|
||||||
|
cid = request_info['root'][0].find('data/card_id').text
|
||||||
|
|
||||||
response = E.response(
|
response = E.response(
|
||||||
E.system_2(
|
E.system_2(
|
||||||
E.data(E.card_number('FFFFFFFFFFFFFFFF', __type="str")),
|
E.data(E.card_number(conv.to_konami_id(cid), __type="str")),
|
||||||
E.result(0, __type="s32"),
|
E.result(0, __type="s32"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
101
utils/card.py
Normal file
101
utils/card.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# https://bsnk.me/eamuse/
|
||||||
|
|
||||||
|
from Cryptodome.Cipher import DES3
|
||||||
|
|
||||||
|
|
||||||
|
KEY = bytes(i * 2 for i in b"?I'llB2c.YouXXXeMeHaYpy!")
|
||||||
|
IV = bytes(8)
|
||||||
|
|
||||||
|
valid_characters = "0123456789ABCDEFGHJKLMNPRSTUWXYZ"
|
||||||
|
|
||||||
|
|
||||||
|
def enc_des(uid):
|
||||||
|
cipher = DES3.new(KEY, DES3.MODE_CBC, IV)
|
||||||
|
return cipher.encrypt(uid)
|
||||||
|
|
||||||
|
|
||||||
|
def dec_des(uid):
|
||||||
|
cipher = DES3.new(KEY, DES3.MODE_CBC, IV)
|
||||||
|
return cipher.decrypt(uid)
|
||||||
|
|
||||||
|
|
||||||
|
def checksum(data):
|
||||||
|
chk = sum(data[i] * (i % 3 + 1) for i in range(15))
|
||||||
|
while chk > 31:
|
||||||
|
chk = (chk >> 5) + (chk & 31)
|
||||||
|
return chk
|
||||||
|
|
||||||
|
|
||||||
|
def pack_5(data):
|
||||||
|
data = "".join(f"{i:05b}" for i in data)
|
||||||
|
if len(data) % 8 != 0:
|
||||||
|
data += "0" * (8 - (len(data) % 8))
|
||||||
|
return bytes(int(data[i:i+8], 2) for i in range(0, len(data), 8))
|
||||||
|
|
||||||
|
|
||||||
|
def unpack_5(data):
|
||||||
|
data = "".join(f"{i:08b}" for i in data)
|
||||||
|
if len(data) % 5 != 0:
|
||||||
|
data += "0" * (5 - (len(data) % 5))
|
||||||
|
return bytes(int(data[i:i+5], 2) for i in range(0, len(data), 5))
|
||||||
|
|
||||||
|
|
||||||
|
def to_konami_id(uid):
|
||||||
|
assert len(uid) == 16, "UID must be 16 bytes"
|
||||||
|
|
||||||
|
if uid.upper().startswith("E004"):
|
||||||
|
card_type = 1
|
||||||
|
elif uid.upper().startswith("0"):
|
||||||
|
card_type = 2
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid UID prefix")
|
||||||
|
|
||||||
|
kid = bytes.fromhex(uid)
|
||||||
|
assert len(kid) == 8, "ID must be 8 bytes"
|
||||||
|
|
||||||
|
out = bytearray(unpack_5(enc_des(kid[::-1]))[:13]) + bytes(3)
|
||||||
|
|
||||||
|
out[0] ^= card_type
|
||||||
|
out[13] = 1
|
||||||
|
for i in range(1, 14):
|
||||||
|
out[i] ^= out[i - 1]
|
||||||
|
out[14] = card_type
|
||||||
|
out[15] = checksum(out)
|
||||||
|
|
||||||
|
return "".join(valid_characters[i] for i in out)
|
||||||
|
|
||||||
|
|
||||||
|
def to_uid(konami_id):
|
||||||
|
if konami_id[14] == "1":
|
||||||
|
card_type = 1
|
||||||
|
elif konami_id[14] == "2":
|
||||||
|
card_type = 2
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid ID")
|
||||||
|
|
||||||
|
assert len(konami_id) == 16, f"ID must be 16 characters"
|
||||||
|
assert all(i in valid_characters for i in konami_id), "ID contains invalid characters"
|
||||||
|
card = [valid_characters.index(i) for i in konami_id]
|
||||||
|
assert card[11] % 2 == card[12] % 2, "Parity check failed"
|
||||||
|
assert card[13] == card[12] ^ 1, "Card invalid"
|
||||||
|
assert card[15] == checksum(card), "Checksum failed"
|
||||||
|
|
||||||
|
for i in range(13, 0, -1):
|
||||||
|
card[i] ^= card[i - 1]
|
||||||
|
|
||||||
|
card[0] ^= card_type
|
||||||
|
|
||||||
|
card_id = dec_des(pack_5(card[:13])[:8])[::-1]
|
||||||
|
card_id = card_id.hex().upper()
|
||||||
|
|
||||||
|
if card_type == 1:
|
||||||
|
assert card_id[:4] == "E004", "Invalid card type"
|
||||||
|
elif card_type == 2:
|
||||||
|
assert card_id[0] == "0", "Invalid card type"
|
||||||
|
return card_id
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
assert to_konami_id("0000000000000000") == "007TUT8XJNSSPN2P", "To KID failed"
|
||||||
|
assert to_uid("007TUT8XJNSSPN2P") == "0000000000000000", "From KID failed"
|
||||||
|
assert to_uid(to_konami_id("000000100200F000")) == "000000100200F000", "Roundtrip failed"
|
Loading…
x
Reference in New Issue
Block a user