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
exceptions, but it should be a good enough starting point for your own version.</p>
<pre></pre>{% highlight 'python' %}
import binascii
from Crypto.Cipher import DES3
import binascii
from Crypto.Cipher import DES3
KEY = b"" # Check the DES section for this
_KEY = bytes(i * 2 for i in KEY) # Preprocess the key
KEY = b"?I'llB2c.YouXXXeMeHaYpy!"
_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)
return cipher.encrypt(uid)
def dec_des(uid):
def dec_des(uid):
cipher = DES3.new(_KEY, DES3.MODE_CBC, iv=b'\0' * 8)
return cipher.decrypt(uid)
def checksum(data):
chk = sum(data[i] * (i % 3 + 1) for i in range(15))
def checksum(data):
chk = sum(data[i] * (i % 3 + 1) for i in range(15))
while chk > 31:
while 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)
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))
def unpack_5(data):
def unpack_5(data):
data = "".join(f"{i:08b}" for i in data)
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))
def to_konami_id(uid):
def to_konami_id(uid):
assert len(uid) == 16, "UID must be 16 bytes"
if uid.upper().startswith("E004"):
card_type = 1
card_type = 1
elif uid.upper().startswith("0"):
card_type = 2
card_type = 2
else:
raise ValueError("Invalid UID prefix")
raise ValueError("Invalid UID prefix")
kid = binascii.unhexlify(uid)
assert len(kid) == 8, "ID must be 8 bytes"
@ -71,20 +71,20 @@ def to_konami_id(uid):
out[0] ^= card_type
out[13] = 1
for i in range(1, 14):
out[i] ^= out[i - 1]
out[i] ^= out[i - 1]
out[14] = card_type
out[15] = checksum(out)
return "".join(ALPHABET[i] for i in out)
def to_uid(konami_id):
def to_uid(konami_id):
if konami_id[14] == "1":
card_type = 1
card_type = 1
elif konami_id[14] == "2":
card_type = 2
card_type = 2
else:
raise ValueError("Invalid ID")
raise ValueError("Invalid ID")
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"
@ -94,7 +94,7 @@ def to_uid(konami_id):
assert card[15] == checksum(card), "Checksum failed"
for i in range(13, 0, -1):
card[i] ^= card[i - 1]
card[i] ^= card[i - 1]
card[0] ^= card_type
@ -102,17 +102,17 @@ def to_uid(konami_id):
card_id = binascii.hexlify(card_id).decode().upper()
if card_type == 1:
assert card_id[:4] == "E004", "Invalid card type"
assert card_id[:4] == "E004", "Invalid card type"
elif card_type == 2:
assert card_id[0] == "0", "Invalid card type"
assert card_id[0] == "0", "Invalid card type"
return card_id
if __name__ == "__main__":
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"
{% endhighlight %}</pre>
{% endhighlight %}</pre>
</details>
<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>
@ -253,13 +253,11 @@ card[15] = <a href="#checksum">checksum(card)</a></code></pre>
<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
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
<code>strings</code>. <span style="color: white">Alternatively, check the source of this page.</span> The key
contains characters that are all within the ASCII range. Before we can use it with DES, the value of every byte
needs doubled. This was presumably done to give the values more range, but I sincerely doubt it adds any
additional security.
a totally null <code>IV</code>. The encryption key is <code>?I'llB2c.YouXXXeMeHaYpy!</code>. The key consists of
characters that are all within the ASCII range. Before we can use it with DES, the value of every byte needs
doubled. This was presumably done to give the values more range, but I sincerely doubt it adds any additional
security.
</p>
<!-- soundvoltex.dll:0x102d3e2d -->
<details>
<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.

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>C:\WINDOWS\system32\regini.exe S:\default_regset.txt</code></li>
<li><code>c:\System\Execute\mxsegaboot.exe</code></li>
<!-- Investigate amDongleSetAuthConfig->FUN_00412ae0 -->
<!-- TODO: Investigate amDongleSetAuthConfig->FUN_00412ae0 -->
</ul>
{% endblock %}

View File

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