# Verification

How to establish that a document is what it claims to be.
**hexane** · <https://hexane.cc>

Publishing from a leaked archive carries an obligation: show your reader that
the document is authentic, and show them how you know. This archive preserves
the material needed to do that. Use it.

---

## 1. Email: the header chain

Every message keeps its original headers. Four of them do the work.

### `Received` — the routing chain

Read **bottom-up**: the lowest `Received` line is the first server that saw
the message; the top one is the last.

```
Received: from mail.afd.de (mail.afd.de [1.2.3.4])
        by mx.example.de with ESMTPS id abc123
        for <recipient@example.de>; Mon, 3 Jun 2024 10:22:11 +0200
```

What to check:

- Do the timestamps increase monotonically going up?
- Does the top `Received` match the recipient's actual mail provider?
- Is there a gap or a re-injection (a second `Received` from an unexpected
  host)? That suggests forwarding, not forgery.
- Do the hostnames resolve to plausible IPs?

### `DKIM-Signature` — the cryptographic claim

A DKIM signature is created by the sending domain's mail server and covers
specified headers plus the body hash.

```
DKIM-Signature: v=1; a=rsa-sha256; d=afd.de; s=selector1;
    h=from:to:subject:date:message-id; bh=...; b=...
```

Verify with:

```bash
# save the message, then
opendkim-testmsg < message.eml
# or
python3 -c "
import dkim
print(dkim.verify(open('message.eml','rb').read()))
"
```

**Caveat that matters:** a valid DKIM signature proves the message passed
through that domain's mail server, not that the named person wrote it. It
also cannot be re-verified if the signing key has since been rotated or the
DNS record removed — check whether the selector still exists:

```bash
dig +short selector1._domainkey.afd.de TXT
```

If the record is gone, the signature is still evidence of the claim at send
time but you cannot re-verify it today. Say so.

### `Authentication-Results` — the receiving server's verdict

Added by the recipient's server. Shows SPF, DKIM and DMARC results **at
delivery time**, which is stronger than a re-check today.

```
Authentication-Results: mx.example.de;
    spf=pass smtp.mailfrom=afd.de;
    dkim=pass header.d=afd.de;
    dmarc=pass
```

### `Message-ID` — identity and threading

```
Message-ID: <20170105172637.6991520874@afd-mail.hosting.plutex.de>
```

The domain part is often the sending infrastructure, which is itself useful:
it tells you which mail system the party used at that time.

Threading: `In-Reply-To` and `References` link messages. A thread is much
harder to fabricate than a single message, because every message must carry
consistent ids.

---

## 2. Documents: metadata

### PDFs

```bash
pdfinfo document.pdf
```

Look at:

| field | what it tells you |
|---|---|
| `Producer` | software that made it (`Microsoft® Word`, `ScanSnap`, `LibreOffice`) |
| `Creator` | application |
| `CreationDate` | when the file was made |
| `ModDate` | when it was last changed — **a `ModDate` later than `CreationDate` means it was edited** |
| `Author` | often a real person's account name |
| `Pages`, `Page size` | sanity check |

```bash
# embedded XMP metadata (often richer)
exiftool document.pdf
```

**Red flags:** `Producer: iText` or similar library output (generated, not
scanned), missing dates, `Author` fields that contradict the document's
claimed origin.

### Office documents

`.docx`/`.xlsx` are ZIP archives. Author and revision history live inside:

```bash
unzip -p doc.docx docProps/core.xml | xmllint --format -
unzip -p doc.docx docProps/app.xml  | xmllint --format -
```

`core.xml` gives `creator`, `lastModifiedBy`, `created`, `modified`,
`revision`. **`lastModifiedBy` is often the most revealing field in the whole
document.**

Track changes, if present:

```bash
unzip -p doc.docx word/document.xml | rg -o '<w:(ins|del) [^>]*>' | head
```

### Images

```bash
exiftool photo.jpg | rg -i 'date|camera|software|gps'
```

Scans usually have no camera EXIF but do have scanner software tags.
Screenshots often reveal the OS and sometimes the application.

---

## 3. Cross-corroboration

The strongest verification is internal consistency across independent files.

- **Same amount, different documents.** An invoice in `03_DOCUMENTS/` and a
  payment confirmation in `01_EMAIL/` should agree on figure, date and
  reference number.
- **Same event, different mailboxes.** A meeting discussed in two mailboxes
  with consistent dates and attendees is much stronger than one message.
- **Party records vs published accounts.** `Rechenschaftsbericht` documents
  can be checked against the published party accounts.
- **Third-party records.** Company registers (`Handelsregister`), court
  dockets, land registry, published minutes.

Do at least one of these before publishing a serious claim.

---

## 4. What this archive cannot prove

Be honest with your reader about the limits:

- **It cannot prove authorship by a named individual** unless the message is
  DKIM-signed by that person's own domain and the content is consistent with
  their role.
- **It cannot prove a document is unaltered** if it is a scan or a PDF with a
  later `ModDate`.
- **It cannot prove completeness.** The archive is partial.
- **It cannot prove an allegation is true.** An email alleging embezzlement
  is evidence that the allegation was made, not that the money moved.

---

## 5. A defensible paragraph

When you publish, something like this does the work:

> The document is an email dated 3 June 2024, sent from
> `name@afd.de` to `recipient@example.de`, with a valid DKIM signature for
> the `afd.de` domain and a `Received` chain consistent with delivery through
> the party's mail server. Its `Message-ID` places it in the same thread as
> [other message], which corroborates the sequence of events. The attached
> invoice (`Rechnung_685183.pdf`) carries matching metadata and a reference
> number that appears in a second, independently obtained email.

That is verification. "We obtained documents" is not.

---

## 6. Tools

| tool | use |
|---|---|
| `opendkim-testmsg`, `python-dkim` | verify DKIM |
| `dig` | check whether the signing DNS record still exists |
| `pdfinfo`, `exiftool` | PDF and image metadata |
| `unzip` + `xmllint` | Office document metadata |
| `notmuch` | threading and provenance across a mailbox |
| `mailauth` (node) | full SPF/DKIM/DMARC evaluation |

---

**hexane** · <https://hexane.cc>
