From 1d62abc9f8aaf1ced766024a829b34f75c90d6d0 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Thu, 17 Nov 2022 18:11:21 +0000 Subject: [PATCH] Yolo encryption keys --- images/flags/card.png | Bin 1440 -> 0 bytes images/flags/xeai.png | Bin 4921 -> 0 bytes templates/pages/cardid.html | 68 ++++++++++---------- templates/pages/flags.html | 7 -- templates/pages/sega/software/mxmaster.html | 2 +- templates/pages/transport.html | 4 +- 6 files changed, 36 insertions(+), 45 deletions(-) delete mode 100644 images/flags/card.png delete mode 100644 images/flags/xeai.png delete mode 100644 templates/pages/flags.html diff --git a/images/flags/card.png b/images/flags/card.png deleted file mode 100644 index 1ea91565d2e945d1929362b7fb3d5ffd35da6a7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1440 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 diff --git a/templates/pages/cardid.html b/templates/pages/cardid.html index b3f5fb6..68aafa7 100644 --- a/templates/pages/cardid.html +++ b/templates/pages/cardid.html @@ -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.

{% 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 %}
+    {% endhighlight %}
 
 

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.

@@ -253,13 +253,11 @@ card[15] = checksum(card)

The DES scheme used

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 IV. The key is quite easy to find if you hit the right binaries with - strings. Alternatively, check the source of this page. 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 IV. The encryption key is ?I'llB2c.YouXXXeMeHaYpy!. 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.

-
I'm curious how Bemani implemented this in their own code!

Curiosity is a great thing. Unfortunately, this is code that is implement within the game specific DLL files. diff --git a/templates/pages/flags.html b/templates/pages/flags.html deleted file mode 100644 index 02ecaa7..0000000 --- a/templates/pages/flags.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "konami.html" %} -{% block title %}Curious flags{% endblock %} -{% block body %} -
- - -{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/software/mxmaster.html b/templates/pages/sega/software/mxmaster.html index 0085880..eef64e1 100644 --- a/templates/pages/sega/software/mxmaster.html +++ b/templates/pages/sega/software/mxmaster.html @@ -17,7 +17,7 @@

  • s:\mxgdeliver.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}
  • C:\WINDOWS\system32\regini.exe S:\default_regset.txt
  • c:\System\Execute\mxsegaboot.exe
  • - + {% endblock %} \ No newline at end of file diff --git a/templates/pages/transport.html b/templates/pages/transport.html index e6dc31d..5159478 100644 --- a/templates/pages/transport.html +++ b/templates/pages/transport.html @@ -56,8 +56,8 @@ uint32_t prng() { trying to roll your own!

    -

    Our per-packet key is then generated using md5(seconds | salt | ENC_KEY). Identifying - ENC_KEY is left as an exercise for the reader, however should not be especially challenging. +

    Our per-packet key is then generated using md5(seconds | salt | ENC_KEY). ENC_KEY is + currently 69d74627d985ee2187161570d08d93b12455035b6df0d8205df5 for all games.

    Source code details