A Python port of the Invisible Internet Project (I2P)
at main 85 lines 2.1 kB view raw
1"""SU3 file format parser — signed update file format. 2 3Parses the header of I2P's SU3 update files which contain 4signed router updates, plugins, and other content. 5 6Ported from net.i2p.crypto.SU3File. 7""" 8 9from __future__ import annotations 10 11import struct 12from dataclasses import dataclass 13 14_SU3_MAGIC = b"I2Psu3" 15_MIN_HEADER_SIZE = 40 16 17 18@dataclass 19class SU3Header: 20 """Parsed SU3 file header.""" 21 magic: str 22 format_version: int 23 sig_type: int 24 sig_length: int 25 content_type: int 26 file_type: int 27 version_length: int 28 signer_length: int 29 content_length: int 30 31 32def parse_su3_header(data: bytes) -> SU3Header | None: 33 """Parse an SU3 file header from raw bytes. 34 35 Returns None if the data is too short or has invalid magic. 36 """ 37 if len(data) < _MIN_HEADER_SIZE: 38 return None 39 40 # Check magic (first 6 bytes) 41 if data[:6] != _SU3_MAGIC: 42 return None 43 44 # Parse header fields 45 # Byte 6: unused 46 # Byte 7: format version (currently 0) 47 format_version = data[7] 48 49 # Bytes 8-9: signature type (big-endian uint16) 50 sig_type = struct.unpack(">H", data[8:10])[0] 51 52 # Bytes 10-11: signature length 53 sig_length = struct.unpack(">H", data[10:12])[0] 54 55 # Byte 12: unused 56 # Byte 13: content type 57 content_type = data[13] if len(data) > 13 else 0 58 59 # Byte 14: unused 60 # Byte 15: file type 61 file_type = data[15] if len(data) > 15 else 0 62 63 # Byte 16: version string length 64 version_length = data[16] if len(data) > 16 else 0 65 66 # Byte 17: unused 67 # Byte 18: signer ID length 68 signer_length = data[18] if len(data) > 18 else 0 69 70 # Bytes 20-27: content length (big-endian uint64) 71 content_length = 0 72 if len(data) >= 28: 73 content_length = struct.unpack(">Q", data[20:28])[0] 74 75 return SU3Header( 76 magic=_SU3_MAGIC.decode("ascii"), 77 format_version=format_version, 78 sig_type=sig_type, 79 sig_length=sig_length, 80 content_type=content_type, 81 file_type=file_type, 82 version_length=version_length, 83 signer_length=signer_length, 84 content_length=content_length, 85 )