counted

Counted überprüfen

Ende-zu-Ende-Verschlüsselung ist nur etwas wert, wenn der Code in deinem Browser der Code ist, den wir angeblich ausliefern. Diese Seite gibt es, damit du uns nicht einfach glauben musst.

Was veröffentlicht wird

Jede Version von Counted wird einmal gebaut, in einer eingefrorenen Umgebung, und vom Ergebnis wird ein Fingerabdruck erstellt: der Server, das WebAssembly-Modul, sein JavaScript und jede Datei der App, als SHA-256. Die Liste wird von genau der Version ausgeliefert, die gerade läuft:

https://counted.fr/SHA256SUMS.txt

Jede Zeile ist der Fingerabdruck einer Datei und ihr Pfad auf counted.fr: assets/web_bg-….wasm, assets/web-….js, die Schriften und Stylesheets. Dieselbe Liste steht in den Notizen jedes Releases, getrennt vom Server, der sie ausliefert.

Prüfe, was du erhältst

Lade in einem Terminal die Liste und jede darin genannte Datei herunter und vergleiche:

curl -sO https://counted.fr/SHA256SUMS.txt
for f in $(awk '$2 != "server" {print $2}' SHA256SUMS.txt); do
  curl -s --create-dirs -o "$f" "https://counted.fr/$f"
done
sha256sum -c --ignore-missing SHA256SUMS.txt

Jede Zeile muss mit OK enden. server ist die ausführbare Datei des Servers; sie wird nicht ausgeliefert, ihr Fingerabdruck steht zum Vergleich mit einem Build dort.

Bau es selbst

Der Build ist reproduzierbar: Basis-Images und Compiler per Digest festgelegt, gleiche Pfade, gleiche Flags. Der Quellcode des Clients ist öffentlich unter github.com/counted-labs/counted, ein Tag pro Version, unter der Lizenz AGPL-3.0. Damit bauen drei Befehle nach, was diese Seite ausliefert, und vergleichen:

git clone --branch vX.Y.Z https://github.com/counted-labs/counted.git && cd counted
docker buildx build --platform linux/amd64 -f Dockerfile.client --target sums --output type=local,dest=out .
curl -s https://counted.fr/SHA256SUMS.txt | grep -v '  server$' | diff - out/SHA256SUMS.txt

Ein leerer Diff bedeutet, dass jede Datei, die dein Browser erhält, Byte für Byte das ist, was diese Quellen erzeugen. Die Zeile server ist das native Binary: Sein Code ist nicht veröffentlicht, es wird beim Vergleich übersprungen, und es sieht deine Daten nie im Klartext - alles wird auf deinem Gerät verschlüsselt, bevor es gesendet wird. Jedes GitHub-Release enthält außerdem die SHA256SUMS.txt seiner Version, eine von diesem Server unabhängige Kopie. Wir führen denselben Nachbau selbst durch, ohne Cache, für jedes Release.

Prüfe die Signatur

Jede SHA256SUMS.txt wird von unserer Build-Pipeline mit Sigstore signiert, und die Signatur wird in ein öffentliches Log geschrieben, an das nur angehängt werden kann: Die Liste eines Releases lässt sich nachträglich nicht austauschen, ohne dass es auffällt. Mit cosign:

base=https://github.com/counted-labs/counted/releases/download/vX.Y.Z
curl -sLO $base/SHA256SUMS.txt -sLO $base/SHA256SUMS.txt.sigstore.json
cosign verify-blob --bundle SHA256SUMS.txt.sigstore.json \
  --certificate-identity "https://gitlab.com/jbosi/counted//.gitlab-ci.yml@refs/heads/main" \
  --certificate-oidc-issuer https://gitlab.com SHA256SUMS.txt
curl -s https://counted.fr/SHA256SUMS.txt | cmp - SHA256SUMS.txt

Verified OK, danach keine Ausgabe von cmp: Die Liste, die diese Seite ausliefert, ist genau die, die der Build dieses Releases signiert hat. Die Signatur beweist, woher die Liste stammt, nicht dass der Code sicher ist - dafür sind die beiden Prüfungen oben da.

Ohne uns geprüft

Zwei Prüfungen laufen auf den Rechnern von GitHub, die nichts mit unseren teilen, und ihre Ergebnisse sind öffentlich:

  • Bei jedem Release wird der Client aus seinem Tag neu gebaut und mit der signierten SHA256SUMS.txt dieses Releases verglichen.
  • Alle 6 Stunden wird die Liste, die counted.fr ausliefert, mit der signierten Liste eines veröffentlichten Releases verglichen; jede aufgeführte Datei muss unverändert ausgeliefert werden, und die Seiten der App dürfen nur Dateien von der Liste laden.

Die mobilen Apps

Die Apps für Android und iOS werden aus denselben Quellen gebaut. Was sich prüfen lässt, hängt vom Store ab:

  • F-Droid baut jede Version aus dem öffentlichen Repository neu und verteilt unsere APK nur, wenn der eigene Build dieselben Bytes ergibt, abgesehen von der Signatur.
  • Google Play signiert die App mit einem eigenen Schlüssel, dessen Zertifikat unten steht: Es beweist, dass eine Kopie von Play stammt, aber diese Kopie lässt sich noch nicht mit einem Build vergleichen.
  • Der App Store verschlüsselt jede Kopie für das Gerät, das sie installiert: Niemand kann sie mit einem Build vergleichen, auch wir nicht. Kennungen: Team UK936HFQ24, App fr.counted.app.

Signaturzertifikat der F-Droid-APK und der APK, die den GitHub-Releases beiliegt, als SHA-256:

D8:D4:02:6F:49:6F:3C:21:54:F1:38:E8:17:10:33:2E:A5:28:8A:AA:B8:56:7A:2F:8D:0E:71:3D:E1:D5:93:E8

Um die auf deinem Handy installierte App zu prüfen, vergleicht die App AppVerifier ihr Zertifikat mit diesem. Von einem Computer aus:

adb pull "$(adb shell pm path fr.counted.app | head -1 | cut -d: -f2)" counted.apk
apksigner verify --print-certs counted.apk | grep SHA-256

Signaturzertifikat von Google Play, als SHA-256:

4C:1E:7D:F5:2C:FB:D6:03:14:C2:0B:E4:AA:7E:9E:7D:30:19:1C:50:24:3B:F5:09:1A:21:F4:B1:30:98:A6:DC

Was das beweist

  • Der Code, den dein Browser ausführt, ist der Code, dessen Fingerabdruck veröffentlicht ist.
  • Zwei Personen, die gleichzeitig prüfen, erhalten denselben Code.
  • Eine aus ihren Quellen neu gebaute Version ergibt dieselben Dateien - zwischen dem Code und dem, was ausgeliefert wird, wurde also nichts hinzugefügt.

Was das nicht beweist

  • Dass der Code korrekt ist: Ein Fingerabdruck bestätigt die Identität einer Datei, nicht ihre Qualität.
  • Dass eine andere Datei, die einer einzelnen Person ausgeliefert wird, auffallen würde: Die automatischen Prüfungen sehen, was alle erhalten, und dein Browser prüft von sich aus nichts. Wenn dich das beunruhigt, nutze die mobile App, deren Code bei der Installation feststeht.
  • Was der Server tut: Sein Code ist nicht öffentlich. Er erhält nur verschlüsselte Daten, aber wie er mit Metadaten umgeht, lässt sich von außen nicht prüfen. Unsere Sicherheitsrichtlinie sagt zu jeder Behauptung, was sie belegt.

Ein Fingerabdruck stimmt nicht? Schreib uns mit der Zeile und dem Datum.