counted

Verificar Counted

El cifrado de extremo a extremo solo vale algo si el código que se ejecuta en tu navegador es el que decimos servir. Esta página existe para que no tengas que creernos sin más.

Qué se publica

Cada versión de Counted se compila una sola vez, en un entorno congelado, y del resultado se toma la huella: el servidor, el módulo WebAssembly, su JavaScript y cada archivo de la app, en SHA-256. La lista la sirve la propia versión que está en marcha:

https://counted.fr/SHA256SUMS.txt

Cada línea es la huella de un archivo y su ruta en counted.fr: assets/web_bg-….wasm, assets/web-….js, las fuentes y las hojas de estilo. La misma lista está en las notas de cada versión, lejos del servidor que la sirve.

Comprueba lo que recibes

Desde un terminal, descarga la lista y cada archivo que nombra, y compara:

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

Cada línea debe terminar en OK. server es el ejecutable del servidor; no se sirve, su huella está ahí para compararla con una compilación.

Compílalo tú mismo

La compilación es reproducible: imágenes base y compilador fijados por digest, mismas rutas, mismos flags. El código fuente del cliente es público en github.com/counted-labs/counted, una etiqueta por versión, bajo la licencia AGPL-3.0. A partir de él, tres comandos recompilan lo que sirve este sitio y comparan:

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

Un diff vacío significa que cada archivo que recibe tu navegador es, byte a byte, lo que producen esas fuentes. La línea server es el binario nativo: su código no se publica, se excluye de la comparación y nunca ve tus datos en claro - todo se cifra en tu dispositivo antes de enviarse. Cada versión en GitHub incluye también el SHA256SUMS.txt de su versión, una copia independiente de este servidor. Nosotros hacemos la misma recompilación, sin caché, en cada versión.

Comprueba la firma

Cada SHA256SUMS.txt lo firma nuestra cadena de compilación con Sigstore, y la firma se escribe en un registro público en el que solo se puede añadir: la lista de una versión no puede sustituirse después sin que se note. Con 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 y luego ninguna salida de cmp: la lista que sirve este sitio es exactamente la que firmó la compilación de esa versión. La firma demuestra de dónde viene la lista, no que el código sea seguro - para eso están las dos comprobaciones de arriba.

Comprobado sin nosotros

Dos comprobaciones se ejecutan en las máquinas de GitHub, que no comparten nada con las nuestras, y sus resultados son públicos:

  • En cada versión, el cliente se recompila desde su etiqueta y se compara con el SHA256SUMS.txt firmado de esa versión.
  • Cada 6 horas, la lista que sirve counted.fr se compara con la lista firmada de una versión publicada; cada archivo de la lista debe servirse sin cambios, y las páginas de la app solo deben cargar archivos de la lista.

Las apps móviles

Las apps de Android e iOS se compilan a partir de las mismas fuentes. Lo que se puede comprobar depende de la tienda:

  • F-Droid recompila cada versión desde el repositorio público y solo distribuye nuestro APK si su propia compilación da los mismos bytes, salvo la firma.
  • Google Play firma la app con su propia clave, cuyo certificado aparece abajo: demuestra que una copia viene de Play, pero esa copia aún no puede compararse con una compilación.
  • El App Store cifra cada copia para el dispositivo que la instala: nadie puede compararla con una compilación, ni siquiera nosotros. Identificadores: equipo UK936HFQ24, app fr.counted.app.

Certificado de firma del APK de F-Droid y del adjunto a las versiones de GitHub, en 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

Para comprobar la app instalada en tu teléfono, la app AppVerifier compara su certificado con este. Desde un ordenador:

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

Certificado de firma de Google Play, en 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

Lo que esto demuestra

  • El código que ejecuta tu navegador es el código cuya huella se publica.
  • Dos personas que comprueban a la vez reciben el mismo código.
  • Una versión recompilada desde sus fuentes da los mismos archivos - así que no se añadió nada entre el código y lo que se sirve.

Lo que esto no demuestra

  • Que el código sea correcto: una huella atestigua la identidad de un archivo, no su calidad.
  • Que se detectara un archivo distinto servido a una sola persona: las comprobaciones automáticas ven lo que reciben todos, y tu navegador no comprueba nada por sí mismo. Si eso te preocupa, usa la app móvil, cuyo código queda fijado al instalarla.
  • Lo que hace el servidor: su código no es público. Solo recibe datos cifrados, pero cómo trata los metadatos no puede comprobarse desde fuera. Nuestra política de seguridad indica, para cada afirmación, qué la respalda.

¿Una huella que no coincide? Escríbenos con la línea y la fecha.