> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-5/file-format/forensics-file-format-validation.md).

# Validation

## PNG File Validation with pngcheck

Use `pngcheck` to verify the structural integrity and checksums of a PNG file, which is essential for diagnosing corruption.

```bash
pngcheck -c -v file.png
```

The `-c` flag performs CRC checksum validation on each chunk, while `-v` provides verbose output, listing all chunks found and detailing any structural errors or checksum failures. The `-vtp` flag provides type and position information about chunks in addition to verbose output. This output highlights specific issues (like bad lengths or CRC errors) and their locations, guiding focused repair efforts on the file.

The Cyclic Redundancy Check (CRC) is a crucial part of the PNG format, providing a robust check against errors introduced during transmission or storage. Each chunk in a PNG file consists of length, type, data, and crc. The CRC field is a 4-byte value. This value is calculated over the preceding chunk type code and chunk data fields.

For example, calculating the CRC for a chunk involves processing the 4-byte chunk type code followed by the chunk data. A common approach uses the standard CRC-32 algorithm, which is based on polynomial division and hashes byte sequences to 32-bit values.

```python
import zlib
import struct

def calculate_png_chunk_crc(chunk_type_bytes, chunk_data_bytes):
    """
    Calculates the CRC-32 checksum for a PNG chunk.

    Args:
        chunk_type_bytes: The 4-byte chunk type code as bytes.
        chunk_data_bytes: The chunk data as bytes.

    Returns:
        The 32-bit CRC checksum as an integer.
    """
    # The CRC is calculated over the chunk type code and the chunk data
    data_to_crc = chunk_type_bytes + chunk_data_bytes
    crc = zlib.crc32(data_to_crc) & 0xffffffff # Ensure unsigned 32-bit result
    return crc

# Example usage: IHDR chunk
# An IHDR chunk contains image dimensions, bit depth, colour type, etc.
# Example IHDR data: 128x64, 8-bit depth, Truecolour with alpha, default compression/filter/interlace
chunk_type = b'IHDR'
chunk_data = b'\x00\x00\x00\x80\x00\x00\x00@\x08\x06\x00\x00\x00' # 13 bytes of data

calculated_crc = calculate_png_chunk_crc(chunk_type, chunk_data)
print(f"Calculated CRC: {hex(calculated_crc)}")

# The CRC value stored in the file for this specific IHDR data should be 0xc753165c
expected_crc = 0xc753165c
print(f"Expected CRC:   {hex(expected_crc)}")

if calculated_crc == expected_crc:
    print("CRC matches!")
else:
    print("CRC mismatch!")

# A complete chunk in bytes would be structured as:
# 4 bytes: Length (big-endian integer)
# 4 bytes: Chunk Type (bytes)
# N bytes: Chunk Data (bytes)
# 4 bytes: CRC (big-endian integer)
# For the IHDR example above, the chunk bytes would be:
# length = len(chunk_data) = 13
# chunk_bytes = struct.pack('>I', len(chunk_data)) + chunk_type + chunk_data + struct.pack('>I', calculated_crc)
# print(f"Example IHDR chunk bytes: {chunk_bytes.hex()}")
```

The rationale behind including the CRC field is to allow detection of common transmission errors. This checksum provides a strong assurance that the critical parts of the chunk (its type and data) have not been accidentally modified. If the CRC calculated from the received chunk does not match the CRC stored in the file, `pngcheck` reports a CRC error, indicating potential corruption in that specific chunk. This validation step is vital for ensuring the reliability of PNG files across different systems and storage media.
