VAG fix
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate src/keystore/embedded.rs and KEY_ENTRY_NAMES for mod.rs from REFERENCES/mf_keys.txt"""
|
||||
import re
|
||||
|
||||
MF_KEYS_PATH = "REFERENCES/mf_keys.txt"
|
||||
# Star Line uses same key as SL_A2-A4; we add type 20 so KeyStore.star_line_mf_key is set
|
||||
STAR_LINE_KEY_HEX = "9BF7F89BF8FE78DA"
|
||||
|
||||
def parse_mf_keys(path: str):
|
||||
entries = [] # (type_id, key_u64, name)
|
||||
vag_bytes = []
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
# VAG block: "0000: xx xx ..." or "0020: xx xx ..."
|
||||
if re.match(r"^[0-9A-Fa-f]{4}:\s", line):
|
||||
hex_part = line.split(":", 1)[1].strip()
|
||||
for h in hex_part.split():
|
||||
vag_bytes.append(int(h, 16))
|
||||
continue
|
||||
# KEY:TYPE:NAME
|
||||
parts = line.split(":", 2)
|
||||
if len(parts) != 3:
|
||||
continue
|
||||
key_hex, type_str, name = parts
|
||||
key_hex = key_hex.strip()
|
||||
type_id = int(type_str.strip())
|
||||
name = name.strip()
|
||||
key_u64 = int(key_hex, 16)
|
||||
entries.append((type_id, key_u64, name))
|
||||
# Append Star Line (type 20) so load_kia_keys sets star_line_mf_key
|
||||
entries.append((20, int(STAR_LINE_KEY_HEX, 16), "Star Line"))
|
||||
return entries, vag_bytes
|
||||
|
||||
def u64_to_le_bytes(x: int) -> bytes:
|
||||
return x.to_bytes(8, "little")
|
||||
|
||||
def build_blob(entries, vag_bytes):
|
||||
blob = bytearray()
|
||||
blob.extend(b"KATK")
|
||||
blob.extend((len(entries)).to_bytes(2, "little"))
|
||||
for type_id, key_u64, _ in entries:
|
||||
blob.extend(type_id.to_bytes(4, "little"))
|
||||
blob.extend(u64_to_le_bytes(key_u64))
|
||||
blob.extend(b"VAG ")
|
||||
assert len(vag_bytes) == 64, f"expected 64 VAG bytes, got {len(vag_bytes)}"
|
||||
blob.extend(bytes(vag_bytes))
|
||||
return bytes(blob)
|
||||
|
||||
def rust_byte_literal(blob: bytes, indent=" ") -> str:
|
||||
lines = []
|
||||
for i in range(0, len(blob), 12):
|
||||
chunk = blob[i : i + 12]
|
||||
hexes = ", ".join(f"0x{b:02X}" for b in chunk)
|
||||
lines.append(indent + hexes + ",")
|
||||
return "\n".join(lines)
|
||||
|
||||
def main():
|
||||
entries, vag_bytes = parse_mf_keys(MF_KEYS_PATH)
|
||||
blob = build_blob(entries, vag_bytes)
|
||||
|
||||
# embedded.rs
|
||||
embedded_rs = '''//! Embedded keystore blob (standard encrypted + VAG raw).
|
||||
//! Data is stored as binary to avoid plain-text keys in config.
|
||||
//! Format: "KATK" magic, n_entries (u16 LE), then per entry: type_id (u32 LE), key (u64 LE), then "VAG " + 64 bytes.
|
||||
//! Key bytes are little-endian (LSB first); the resulting u64 matches reference hex (MSB-first notation).
|
||||
//! Generated from REFERENCES/mf_keys.txt by scripts/build_keystore_from_mf_keys.py
|
||||
|
||||
/// Blob: KATK + ''' + str(len(entries)) + ''' entries + VAG 64 bytes.
|
||||
#[rustfmt::skip]
|
||||
pub const KEYSTORE_BLOB: &[u8] = &[
|
||||
'''
|
||||
# Split blob for readable comments: magic + n, then entries (each 12 bytes), then VAG tag + 64
|
||||
off = 0
|
||||
embedded_rs += " // magic + n_entries\n"
|
||||
embedded_rs += rust_byte_literal(blob[0:6], " ") + "\n"
|
||||
off = 6
|
||||
entry_size = 12
|
||||
for i, (ty, key, name) in enumerate(entries):
|
||||
if i % 8 == 0:
|
||||
embedded_rs += f" // entries {i}..\n"
|
||||
embedded_rs += rust_byte_literal(blob[off : off + entry_size], " ") + "\n"
|
||||
off += entry_size
|
||||
embedded_rs += " // VAG tag + 64 bytes\n"
|
||||
embedded_rs += rust_byte_literal(blob[off:], " ") + "\n"
|
||||
embedded_rs += "];\n"
|
||||
|
||||
with open("src/keystore/embedded.rs", "w") as f:
|
||||
f.write(embedded_rs)
|
||||
|
||||
# KEY_ENTRY_NAMES for mod.rs (same order as blob entries)
|
||||
names = [e[2] for e in entries]
|
||||
|
||||
# Update mod.rs: replace KEY_ENTRY_NAMES
|
||||
mod_rs_path = "src/keystore/mod.rs"
|
||||
with open(mod_rs_path) as f:
|
||||
mod_content = f.read()
|
||||
escaped = [n.replace("\\", "\\\\").replace('"', '\\"') for n in names]
|
||||
new_block = "const KEY_ENTRY_NAMES: &[&str] = &[\n " + ",\n ".join(f'"{s}"' for s in escaped) + ",\n];"
|
||||
pattern = r"const KEY_ENTRY_NAMES: &\[&str\] = &\[\n.*?\n\];"
|
||||
mod_content = re.sub(pattern, new_block, mod_content, flags=re.DOTALL)
|
||||
with open(mod_rs_path, "w") as f:
|
||||
f.write(mod_content)
|
||||
|
||||
print(f"Wrote embedded blob with {len(entries)} entries, {len(vag_bytes)} VAG bytes")
|
||||
print(f"Updated KEY_ENTRY_NAMES with {len(names)} names")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user