#!/usr/bin/env python3
"""
Search for MFRC522 key register writes in the SPI export
Registers 0x0C - 0x13 are used for Key A buffer
"""
import csv

print("[*] Searching for MFRC522 key register writes...\n")

with open('export.csv', 'r') as f:
    reader = list(csv.DictReader(f))

print(f"[+] Loaded {len(reader)} rows\n")

# MFRC522 register addresses (for writes, set bit 7 = 0, bit 0 = 0)
# Key A registers: 0x0C - 0x13 (6 bytes)
# For writing: addresses would be 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11

key_registers = {
    '0x0c': 'KeyByte0',
    '0x0d': 'KeyByte1', 
    '0x0e': 'KeyByte2',
    '0x0f': 'KeyByte3',
    '0x10': 'KeyByte4',
    '0x11': 'KeyByte5',
}

print("[*] Searching for writes to key registers (0x0C - 0x11)...\n")

key_writes = []
for i, row in enumerate(reader):
    if row['type'] == 'result' and row['mosi']:
        mosi = row['mosi'].lower()
        
        if mosi in key_registers:
            # Found a key register address, next byte should be the key data
            key_reg = key_registers[mosi]
            
            # Get next MOSI byte (the data being written)
            for j in range(i+1, min(i+10, len(reader))):
                next_row = reader[j]
                if next_row['type'] == 'result' and next_row['mosi'] and next_row['mosi'].startswith('0x'):
                    key_data = next_row['mosi']
                    key_writes.append((i, key_reg, mosi, key_data))
                    print(f"Line {i}: {key_reg} ({mosi}) = {key_data}")
                    break

if key_writes:
    print(f"\n[+] Found {len(key_writes)} key register writes!")
    
    # Group into 6-byte keys
    print("\n[*] Attempting to reconstruct 6-byte keys...\n")
    
    # Find sequences of 6 consecutive key writes
    i = 0
    key_sequences = []
    
    while i < len(key_writes):
        if i + 5 < len(key_writes):
            # Check if we have 6 consecutive writes
            seq = key_writes[i:i+6]
            line_start = seq[0][0]
            line_end = seq[5][0]
            
            # If lines are close together, it's likely one key
            if line_end - line_start < 100:
                key_bytes = [int(kw[3], 16) for kw in seq]
                key_hex = ''.join(f'{b:02x}' for b in key_bytes)
                key_sequences.append((line_start, key_hex, key_bytes))
                
                print(f"Key at line {line_start}: {key_hex}")
                i += 6
            else:
                i += 1
        else:
            break
    
    if key_sequences:
        print(f"\n{'='*70}")
        print(f"FOUND {len(key_sequences)} complete 6-byte keys!")
        print(f"{'='*70}\n")
        
        for idx, (line, hex_key, bytes_key) in enumerate(key_sequences):
            print(f"Key #{idx+1} (line {line}): {hex_key}")
            
            # Split into two 3-byte values (LCG outputs)
            key1 = (bytes_key[0] << 16) | (bytes_key[1] << 8) | bytes_key[2]
            key2 = (bytes_key[3] << 16) | (bytes_key[4] << 8) | bytes_key[5]
            
            print(f"  Split: [{key1:06x}] [{key2:06x}]")
            print()
        
        # Try to crack the LCG from the LAST key (keys 4-5 used for sector 34)
        if len(key_sequences) >= 3:
            print("[*] Attempting to crack passcode from keys...")
            
            # The 3rd key set should be keys[4] and keys[5]
            last_key_bytes = key_sequences[-1][2]
            key4 = (last_key_bytes[0] << 16) | (last_key_bytes[1] << 8) | last_key_bytes[2]
            key5 = (last_key_bytes[3] << 16) | (last_key_bytes[4] << 8) | last_key_bytes[5]
            
            print(f"Using last key: [{key4:06x}] [{key5:06x}]")
            
            # Try to crack passcode
            import sys
            sys.path.append('.')
            from crack_all_sequences import crack_from_two_outputs
            
            passcode = crack_from_two_outputs(key4, key5)
            
            if passcode:
                print(f"\n{'='*70}")
                print(f"PASSCODE FOUND: {passcode}")
                print(f"{'='*70}")
            else:
                print("\n[-] Could not crack passcode from these values")
                print("[!] They might not be consecutive LCG outputs")
else:
    print("\n[-] No key register writes found")
    print("[*] Trying alternative: look for FIFO writes (0x09)...\n")
    
    for i, row in enumerate(reader[:1000]):  # Check first 1000 lines
        if row['type'] == 'result' and row['mosi']:
            mosi = row['mosi'].lower()
            if mosi == '0x09':
                print(f"FIFO write at line {i}")
