Yolo encryption keys

This commit is contained in:
Bottersnike 2022-11-17 18:11:21 +00:00
parent a3e32f95a6
commit 1d62abc9f8
6 changed files with 36 additions and 45 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -10,58 +10,58 @@
cases too. It's not great code by any stretch, and it liberally uses assertions rather than proper cases too. It's not great code by any stretch, and it liberally uses assertions rather than proper
exceptions, but it should be a good enough starting point for your own version.</p> exceptions, but it should be a good enough starting point for your own version.</p>
<pre></pre>{% highlight 'python' %} <pre></pre>{% highlight 'python' %}
import binascii import binascii
from Crypto.Cipher import DES3 from Crypto.Cipher import DES3
KEY = b"" # Check the DES section for this KEY = b"?I'llB2c.YouXXXeMeHaYpy!"
_KEY = bytes(i * 2 for i in KEY) # Preprocess the key _KEY = bytes(i * 2 for i in KEY) # Preprocess the key
ALPHABET = "0123456789ABCDEFGHJKLMNPRSTUWXYZ" ALPHABET = "0123456789ABCDEFGHJKLMNPRSTUWXYZ"
def enc_des(uid): def enc_des(uid):
cipher = DES3.new(_KEY, DES3.MODE_CBC, iv=b'\0' * 8) cipher = DES3.new(_KEY, DES3.MODE_CBC, iv=b'\0' * 8)
return cipher.encrypt(uid) return cipher.encrypt(uid)
def dec_des(uid): def dec_des(uid):
cipher = DES3.new(_KEY, DES3.MODE_CBC, iv=b'\0' * 8) cipher = DES3.new(_KEY, DES3.MODE_CBC, iv=b'\0' * 8)
return cipher.decrypt(uid) return cipher.decrypt(uid)
def checksum(data): def checksum(data):
chk = sum(data[i] * (i % 3 + 1) for i in range(15)) chk = sum(data[i] * (i % 3 + 1) for i in range(15))
while chk > 31: while chk > 31:
chk = (chk >> 5) + (chk & 31) chk = (chk >> 5) + (chk & 31)
return chk return chk
def pack_5(data): def pack_5(data):
data = "".join(f"{i:05b}" for i in data) data = "".join(f"{i:05b}" for i in data)
if len(data) % 8 != 0: if len(data) % 8 != 0:
data += "0" * (8 - (len(data) % 8)) data += "0" * (8 - (len(data) % 8))
return bytes(int(data[i:i+8], 2) for i in range(0, len(data), 8)) return bytes(int(data[i:i+8], 2) for i in range(0, len(data), 8))
def unpack_5(data): def unpack_5(data):
data = "".join(f"{i:08b}" for i in data) data = "".join(f"{i:08b}" for i in data)
if len(data) % 5 != 0: if len(data) % 5 != 0:
data += "0" * (5 - (len(data) % 5)) data += "0" * (5 - (len(data) % 5))
return bytes(int(data[i:i+5], 2) for i in range(0, len(data), 5)) return bytes(int(data[i:i+5], 2) for i in range(0, len(data), 5))
def to_konami_id(uid): def to_konami_id(uid):
assert len(uid) == 16, "UID must be 16 bytes" assert len(uid) == 16, "UID must be 16 bytes"
if uid.upper().startswith("E004"): if uid.upper().startswith("E004"):
card_type = 1 card_type = 1
elif uid.upper().startswith("0"): elif uid.upper().startswith("0"):
card_type = 2 card_type = 2
else: else:
raise ValueError("Invalid UID prefix") raise ValueError("Invalid UID prefix")
kid = binascii.unhexlify(uid) kid = binascii.unhexlify(uid)
assert len(kid) == 8, "ID must be 8 bytes" assert len(kid) == 8, "ID must be 8 bytes"
@ -71,20 +71,20 @@ def to_konami_id(uid):
out[0] ^= card_type out[0] ^= card_type
out[13] = 1 out[13] = 1
for i in range(1, 14): for i in range(1, 14):
out[i] ^= out[i - 1] out[i] ^= out[i - 1]
out[14] = card_type out[14] = card_type
out[15] = checksum(out) out[15] = checksum(out)
return "".join(ALPHABET[i] for i in out) return "".join(ALPHABET[i] for i in out)
def to_uid(konami_id): def to_uid(konami_id):
if konami_id[14] == "1": if konami_id[14] == "1":
card_type = 1 card_type = 1
elif konami_id[14] == "2": elif konami_id[14] == "2":
card_type = 2 card_type = 2
else: else:
raise ValueError("Invalid ID") raise ValueError("Invalid ID")
assert len(konami_id) == 16, f"ID must be 16 characters" assert len(konami_id) == 16, f"ID must be 16 characters"
assert all(i in ALPHABET for i in konami_id), "ID contains invalid characters" assert all(i in ALPHABET for i in konami_id), "ID contains invalid characters"
@ -94,7 +94,7 @@ def to_uid(konami_id):
assert card[15] == checksum(card), "Checksum failed" assert card[15] == checksum(card), "Checksum failed"
for i in range(13, 0, -1): for i in range(13, 0, -1):
card[i] ^= card[i - 1] card[i] ^= card[i - 1]
card[0] ^= card_type card[0] ^= card_type
@ -102,17 +102,17 @@ def to_uid(konami_id):
card_id = binascii.hexlify(card_id).decode().upper() card_id = binascii.hexlify(card_id).decode().upper()
if card_type == 1: if card_type == 1:
assert card_id[:4] == "E004", "Invalid card type" assert card_id[:4] == "E004", "Invalid card type"
elif card_type == 2: elif card_type == 2:
assert card_id[0] == "0", "Invalid card type" assert card_id[0] == "0", "Invalid card type"
return card_id return card_id
if __name__ == "__main__": if __name__ == "__main__":
assert to_konami_id("0000000000000000") == "007TUT8XJNSSPN2P", "To KID failed" assert to_konami_id("0000000000000000") == "007TUT8XJNSSPN2P", "To KID failed"
assert to_uid("007TUT8XJNSSPN2P") == "0000000000000000", "From KID failed" assert to_uid("007TUT8XJNSSPN2P") == "0000000000000000", "From KID failed"
assert to_uid(to_konami_id("000000100200F000")) == "000000100200F000", "Roundtrip failed" assert to_uid(to_konami_id("000000100200F000")) == "000000100200F000", "Roundtrip failed"
{% endhighlight %}</pre> {% endhighlight %}</pre>
</details> </details>
<p>e-Amusement cards use 16 digit IDs. KONAMI IDs are also 16 digits. Are they related? Yes! In fact, KONAMI IDs are <p>e-Amusement cards use 16 digit IDs. KONAMI IDs are also 16 digits. Are they related? Yes! In fact, KONAMI IDs are
derived from the ID stored on the e-Amusement card.</p> derived from the ID stored on the e-Amusement card.</p>
@ -253,13 +253,11 @@ card[15] = <a href="#checksum">checksum(card)</a></code></pre>
<h2 id="des">The DES scheme used</h2> <h2 id="des">The DES scheme used</h2>
<p>For whatever reason, Bemani decided that IDs should be encrypted. Thankfully however they used triple DES, which <p>For whatever reason, Bemani decided that IDs should be encrypted. Thankfully however they used triple DES, which
almost certainly has an existing implementation in your language of choice. It is triple DES, in CBC mode, with almost certainly has an existing implementation in your language of choice. It is triple DES, in CBC mode, with
a totally null <code>IV</code>. The key is quite easy to find if you hit the right binaries with a totally null <code>IV</code>. The encryption key is <code>?I'llB2c.YouXXXeMeHaYpy!</code>. The key consists of
<code>strings</code>. <span style="color: white">Alternatively, check the source of this page.</span> The key characters that are all within the ASCII range. Before we can use it with DES, the value of every byte needs
contains characters that are all within the ASCII range. Before we can use it with DES, the value of every byte doubled. This was presumably done to give the values more range, but I sincerely doubt it adds any additional
needs doubled. This was presumably done to give the values more range, but I sincerely doubt it adds any security.
additional security.
</p> </p>
<!-- soundvoltex.dll:0x102d3e2d -->
<details> <details>
<summary>I'm curious how Bemani implemented this in their own code!</summary> <summary>I'm curious how Bemani implemented this in their own code!</summary>
<p>Curiosity is a great thing. Unfortunately, this is code that is implement within the game specific DLL files. <p>Curiosity is a great thing. Unfortunately, this is code that is implement within the game specific DLL files.

View File

@ -1,7 +0,0 @@
{% extends "konami.html" %}
{% block title %}Curious flags{% endblock %}
{% block body %}
<br>
<img src="{{ROOT}}/images/flags/xeai.png" class="graphic">
<img src="{{ROOT}}/images/flags/card.png" class="graphic">
{% endblock %}

View File

@ -17,7 +17,7 @@
<li><code>s:\mxgdeliver.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li> <li><code>s:\mxgdeliver.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>C:\WINDOWS\system32\regini.exe S:\default_regset.txt</code></li> <li><code>C:\WINDOWS\system32\regini.exe S:\default_regset.txt</code></li>
<li><code>c:\System\Execute\mxsegaboot.exe</code></li> <li><code>c:\System\Execute\mxsegaboot.exe</code></li>
<!-- Investigate amDongleSetAuthConfig->FUN_00412ae0 --> <!-- TODO: Investigate amDongleSetAuthConfig->FUN_00412ae0 -->
</ul> </ul>
{% endblock %} {% endblock %}

View File

@ -56,8 +56,8 @@ uint32_t prng() {
trying to roll your own! trying to roll your own!
</p> </p>
</details> </details>
<p>Our per-packet key is then generated using <code>md5(seconds | salt | ENC_KEY)</code>. Identifying <p>Our per-packet key is then generated using <code>md5(seconds | salt | ENC_KEY)</code>. <code>ENC_KEY</code> is
<code>ENC_KEY</code> is left as an exercise for the reader, however should not be especially challenging. currently <code>69d74627d985ee2187161570d08d93b12455035b6df0d8205df5</code> for all games.
</p> </p>
<details> <details>
<summary>Source code details</summary> <summary>Source code details</summary>