2. Amusement IC
Many arcade manufacturers allow players to login to games using physical IC cards, such as SEGA’s AiMe, Bandai’s Banapass, or Konami’s e-Amusement Pass; these cards are incompatible with each other.
Amusement IC is a unified standard spear-headed as a joint venture between SEGA and Konami allowing for a single card to be used across all compatible games. Currently the following companies are participating in the standard:
Amusement IC is abbreviated officially as AICC (Amusement IC Card), but as AIC by the community.
Compatible cards must be FeliCa Lite or FeliCa LiteS. Each card is uniquely identified by a 20-digit access code, as with AiMe cards.
Additionally, the IDm field on the card is used to identify the card using network services. All 8 bytes are used for this purpose.
The DFC field is used to identify the specific card vendor. Current vendors are:
| DFC | Vendor |
|---|---|
00 78 |
SEGA (LiteS) |
00 68 |
Konami (LiteS) |
00 2A |
Bandai Namco Entertainment (LiteS) |
00 3A |
Bandai Namco Games (Lite) |
00 79 |
Nesica |
00 00 |
Reserved for testing |
Bandai Namco Games (FeliCa Edy)
Additionally of note is older Banapass cards, which use FeliCa Edy rather than FeliCa Lite. These cards are not compatible with Amusement IC, however AiMeLib supports them when using a standard card reader, so it is worthwhile being able to identify they. They use the DFC 8C A2.
2.1 SPAD0
Amusement IC cards are expected to contain their access code, encrypted, in SPAD0. The decrypted structure of this data is shown below. The version uses only the lower nibble, and should be set to 0.
Note
The version is only accessible after decryption, so I’m not really sure what purpose, if any, it serves! Maybe it describes the algorithm used for computation of the access code? I’ve never seen it meaningfully used.
The encryption is a basic substitution cipher, with a variable number of iterations. There are 9 S-boxes, however the 9th is reserved as a final masking stage, so all S-box indexes are modulo 8.
The 16th byte of the data is used to identify the cipher parameters. The lower nibble is used as the starting S-box index (modulo 8). The upper nibble is used as the number of iterations of the cipher, plus 7. For example, if the final byte was 13, the initial S-box would be index 3, and 8 iterations would be performed.
Every iteration of the algorithm:
- Substitute every byte in the first 15 bytes using the current S-box
- Rotate the first 15 bytes left 5 bits
- Increment the current S-box index by 5 (modulo 8)
After all iterations have been performed, a final S-box substitution is performed using the 9th S-box, over all 16 bytes.
To decrypt, perform the steps in reverse.
2.1.1 Code
The following code snippet presents a simple implementation of both encryption and decryption.
S_BOX = [...]
S_BOX_INV = [...]
N_TABLES = len(S_BOX) - 1 # Final table is used for masking
ITER_ADD = 5
def rotate_right(data, n_bytes, n_bits):
prior = data[n_bytes - 1]
for i in range(n_bytes):
prior, data[i] = data[i], (data[i] >> n_bits) | ((prior & ((1 << n_bits) - 1)) << (8 - n_bits))
def rotate_left(data, n_bytes, n_bits):
prior = data[0]
for i in range(n_bytes - 1, -1, -1):
prior, data[i] = data[i], ((data[i] & ((1 << (8 - n_bits)) - 1)) << n_bits) | (prior >> (8 - n_bits))
def encrypt(spad):
spad = bytearray(spad)
count = (spad[15] >> 4) + 7
table = spad[15]
for _ in range(count):
for i in range(15):
spad[i] = S_BOX[table % N_TABLES][spad[i]]
rotate_left(spad, 15, 5)
table += ITER_ADD
return bytearray(S_BOX[N_TABLES][i] for i in spad)
def decrypt(spad):
spad = bytearray(S_BOX_INV[N_TABLES][i] for i in spad)
count = (spad[15] >> 4) + 7
table = spad[15] + ITER_ADD * count
for _ in range(count):
table -= ITER_ADD
rotate_right(spad, 15, 5)
for i in range(15):
spad[i] = S_BOX_INV[table % N_TABLES][spad[i]]
return spad