mirror of
https://gitea.tendokyu.moe/eamuse/docs.git
synced 2024-11-23 22:40:57 +01:00
Yolo encryption keys
This commit is contained in:
parent
a3e32f95a6
commit
1d62abc9f8
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.8 KiB |
@ -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.
|
||||
|
@ -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 %}
|
@ -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 %}
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user