2. Amusement IC Access Codes
Amusement IC access codes are divided into three sections.
The first three digits are a company code, the next 12 digits encode a cipher revision number and the card serial, and the final 5 digits are a checksum.
Company Code | Company | Card |
---|---|---|
500 |
SEGA | AiMe, limited edition “not for sale” cards |
501 |
SEGA | AiMe |
510 |
Bandai Namco | Banapass |
520 |
Konami | e-Amusement |
530 |
Taito | Nesica |
The encoding is most easily described with code, so without further ado here is code to both encode and decode access codes:
2.1 Encoding
def crc16(data, bits, initial=0xffff, poly=0x8408):
v = initial
for _ in range(bits):
v = (v >> 1) ^ (poly if ((v ^ data) & 1) else 0)
data >>= 1
return v
def encode_access_code(company: int, serial: int, rev: int) -> None | str:
# Bounds checking
if company > 999: return None
if serial > 99999999999: return None
if rev > 9: return None
body = f"{rev}{serial:011}"
crc_i = crc16(int(f"{company:03}{body}", 16), 15 * 4)
# Extract digits of CRC
crc = [(crc_i // (10**(4-i))) % 10 for i in range(5)]
body = [int(body[i]) * 10 + int(body[i + 1]) for i in range(0, 12, 2)]
# Apply the inner layer of substition
# This uses table [rev]
# The lowest nibble contains rev, which is untouched by this substition
# As such, the first byte only operates on the least siginificant nibble,
# using an appropriately smaller table.
# The following boxes are used for this operation
boxes = ((crc[1] + crc[0]) % 10, crc[1], crc[2], crc[3], crc[4], (crc[4] + crc[1]) % 10)
for n, i in enumerate(body):
if n == 0:
# Preserve the higher nibble
body[n] = (body[n] & 0xf0) | sbtable2[boxes[n]][body[n] & 0x0f]
else:
body[n] = sbtable[rev][boxes[n]][i]
# Apply the outer layer of substition
# This always uses table [4], and as such can mask rev
# The following boxes are used for this operation
boxes = ((crc[3] + crc[2]) % 10, crc[2], crc[3], crc[4], (crc[4] + crc[0]) % 10, crc[1])
for n, i in enumerate(body):
body[n] = sbtable[4][boxes[n]][i]
# Reconstruct the digits to form the access code
body = "".join(f"{i:02}" for i in body)
return f"{co:03}{body}{crc_i:05}"
2.2 Decoding
# See Encoding for the definition of crc16
class Decoded(NamedTuple):
rev: int
serial: int
def decode_access_code(ac: str) -> None | Decoded:
body = [int(ac[i]) * 10 + int(ac[i + 1]) for i in range(3, 15, 2)]
crc = [int(i) for i in ac[15:20]]
# Strip back the outer layer of substitution
# This always uses table [4]
# The following boxes are used for this operation
boxes = ((crc[3] + crc[2]) % 10, crc[2], crc[3], crc[4], (crc[4] + crc[0]) % 10, crc[1])
for n, i in enumerate(body):
body[n] = ibtable[4][boxes[n]][i]
# This reveals the table to be used for the inner layer
rv = body[0] >> 4
# Strip back the inner layer of substituion
# Only the lower nibble is used of the first byte, and as such it has a smaller
# table for operating on single nibbles at a time.
# The following boxes are used for this operation
boxes = ((crc[1] + crc[0]) % 10, crc[1], crc[2], crc[3], crc[4], (crc[4] + crc[1]) % 10)
for n, i in enumerate(body):
if n == 0:
# Preserve the higher nibble
body[n] = (body[n] & 0xf0) | ibtable2[boxes[n]][body[n] & 0x0f]
else:
body[n] = ibtable[rv][boxes[n]][i]
serial = "".join(f"{i:02}" for i in body)
# Validate the CRC before returning the serial number
if crc16(int(ac[0:3] + serial, 16), 15 * 4) != int(ac[15:20]):
return None
return Decoded(int(serial[0]), int(serial[1:]))
2.3 S-Box Tables
The primary S-Box table contains 5 tables of 10 boxes, each 10x10 in dimension (row-major).
The secondary table used for individual nibbles is one table of 10 boxes, each 10x1 in dimension.
2.4 I-Box Tables
The inverse tables can be derived from the S-Box tables with relative triviality. They can alternatively be downloaded pre-computed below.
Generation code:
itable = [[[0 for _ in b] for b in t] for t in stable]
for st, it in zip(stable, itable):
for sb, ib in zip(st, it):
for n, i in enumerate(sb):
ib[i] = n
itable2 = [[0 for _ in b] for b in stable2]
for sb, ib in zip(stable2, itable2):
for n, i in enumerate(sb):
ib[i] = n