age o gpg para cifrar una copia con tar: tamaño, errores y qué se rompe
age no comprime (26 241 480 bytes frente a 21 048 019 de gpg) y tardó 88 ms frente a 860 ms; con un byte dañado, age y tar fallan los dos, mientras que con gpg tar devolvió 0.
Este artículo no contiene enlaces de afiliado.
Si ya leíste tar + gpg, la pregunta siguiente es si age, más moderno y con menos opciones, lo mejora. Se probaron las dos herramientas sobre la misma carpeta.
Condiciones: age 1.1.1 (paquete de Ubuntu) y gpg del sistema, 20 ficheros aleatorios de 1 MiB y un log repetitivo de 5 MiB (25 604 KiB), claves y contraseñas desechables. Script completo al final del artículo. No se probó rendimiento con carpetas grandes, ni Windows o macOS. La prueba de age usa un par de claves porque age -p (contraseña) pide un terminal y no se puede automatizar en un script.
Tamaño y tiempo
| tar + gpg (AES256, contraseña) | tar + age (clave pública) | |
|---|---|---|
| Tamaño | 21 048 019 bytes | 26 241 480 bytes |
| Tiempo de cifrado | 860 ms | 88 ms |
La diferencia de tamaño viene de que gpg comprime antes de cifrar y age no: el log repetitivo ocupó mucho menos con gpg. Si tus datos se comprimen bien, con age tendrás que comprimir tú (tar -czf - carpeta | age ...), cosa que esta prueba no midió. El tiempo también está afectado por esa compresión, así que no es una comparación de velocidad de cifrado pura.
Ninguna de las dos hace copias incrementales: cada copia nueva es completa.
Cuando algo va mal
- Clave equivocada: age salió con código 1 y
no identity matched any of the recipients. gpg con contraseña mala: código 2,Bad session key. Los dos son claros. - Un byte dañado a mitad del fichero: age salió con 1 (
failed to decrypt and authenticate payload chunk) ytar -ttambién falló (2), porque el flujo se corta. Con gpg, el código fue 2 perotar -tdevolvió 0. Con age es más difícil que una tubería dé por buena una copia dañada, aunque conviene usar igualmenteset -o pipefail. - Fichero truncado a 7 000 000 bytes: age 1 y tar 2, mismo mensaje. No se probó el truncado con gpg.
Lo que cambia en la práctica
- Con age cifras con la clave pública y descifras con la privada: no hay contraseña que recordar, pero la clave privada debe guardarse fuera de la copia y respaldada. Sin ella, el fichero es irrecuperable.
- gpg con contraseña es suficiente para una copia personal, y comprime. age es más simple de usar en scripts una vez generada la clave.
Veredicto
Para una carpeta que archivas una vez, cualquiera de las dos sirve; elige age si prefieres claves y mensajes de error simples, y gpg si quieres compresión integrada. Para datos que cambian, usa una herramienta con copias incrementales como restic, y prueba siempre la restauración.
Script completo
test-age-tar.sh:
#!/bin/bash
# tar + age (key pair) backup: size, time, wrong key, corruption, truncation. Usage: test-age-tar.sh WORKDIR. Throwaway keys.
W=$1; rm -rf "$W"; mkdir -p "$W/data"; cd "$W"
for i in $(seq 1 20); do head -c 1048576 /dev/urandom > data/f$i.bin; done; yes "linea de texto repetida" | head -c 5242880 > data/log.txt
echo "origen: $(du -sk data | cut -f1) KiB"; age --version
age-keygen -o clave.txt 2>/dev/null; age-keygen -o otra.txt 2>/dev/null; PUB=$(age-keygen -y clave.txt)
t(){ local s=$(date +%s%N); "$@"; echo "[tiempo: $(( ($(date +%s%N)-s)/1000000 )) ms]" >&2; }
echo "== tar + age"; t bash -c 'tar -cf - data | age -r '"$PUB"' -o copia.tar.age'
ls -l copia.tar.age | awk '{print $5" bytes"}'
echo "== restaurar"; mkdir r; age -d -i clave.txt copia.tar.age | tar -xf - -C r; echo "ficheros: $(find r -type f | wc -l)"
echo "== clave equivocada"; age -d -i otra.txt copia.tar.age >/dev/null 2>err1; echo "exit=$?"; tail -2 err1
echo "== un byte dañado en el medio"; cp copia.tar.age dan.age; printf '\xff' | dd of=dan.age bs=1 seek=10000000 conv=notrunc 2>/dev/null
age -d -i clave.txt dan.age 2>err2 | tar -tf - >/dev/null 2>&1; echo "exit age/tar=${PIPESTATUS[0]}/${PIPESTATUS[1]}"; tail -2 err2
echo "== fichero truncado a la mitad"; head -c 7000000 copia.tar.age > tr.age
age -d -i clave.txt tr.age 2>err3 | tar -tf - >/dev/null 2>&1; echo "exit age/tar=${PIPESTATUS[0]}/${PIPESTATUS[1]}"; tail -2 err3
test-gpg-tar.sh:
#!/bin/bash
# tar + gpg symmetric backup: size, time, wrong passphrase, corruption. Usage: test-gpg-tar.sh WORKDIR. Throwaway passphrase.
W=$1; rm -rf "$W"; mkdir -p "$W/data"; cd "$W"
for i in $(seq 1 20); do head -c 1048576 /dev/urandom > data/f$i.bin; done; yes "linea de texto repetida" | head -c 5242880 > data/log.txt
echo "origen: $(du -sk data | cut -f1) KiB"
t(){ local s=$(date +%s%N); "$@"; echo "[tiempo: $(( ($(date +%s%N)-s)/1000000 )) ms]" >&2; }
echo "== tar + gpg AES256"; t bash -c 'tar -cf - data | gpg --batch --yes --pinentry-mode loopback --passphrase prueba-desechable --symmetric --cipher-algo AES256 -o copia.tar.gpg 2>/dev/null'
ls -l copia.tar.gpg | awk '{print $5" bytes"}'
echo "== día 2: cambia un fichero y se vuelve a hacer todo"; echo cambio >> data/f1.bin
t bash -c 'tar -cf - data | gpg --batch --yes --pinentry-mode loopback --passphrase prueba-desechable --symmetric --cipher-algo AES256 -o copia2.tar.gpg 2>/dev/null'
ls -l copia2.tar.gpg | awk '{print $5" bytes"}'
echo "== restaurar"; mkdir r; gpg --batch --pinentry-mode loopback --passphrase prueba-desechable -d copia.tar.gpg 2>/dev/null | tar -xf - -C r; echo "ficheros: $(find r -type f | wc -l)"
echo "== passphrase mala"; gpg --batch --pinentry-mode loopback --passphrase mala -d copia.tar.gpg >/dev/null 2>/tmp/gpgerr; echo "exit=$?"; tail -1 /tmp/gpgerr
echo "== un byte dañado en el medio"; cp copia.tar.gpg dan.gpg; printf '\xff' | dd of=dan.gpg bs=1 seek=10000000 conv=notrunc 2>/dev/null
gpg --batch --pinentry-mode loopback --passphrase prueba-desechable -d dan.gpg 2>/tmp/gpgerr2 | tar -tf - >/dev/null 2>&1; echo "exit gpg/tar=${PIPESTATUS[0]}/${PIPESTATUS[1]}"; tail -2 /tmp/gpgerr2
echo "== comparación: ficheros que cambian entre copias (cmp de las dos .gpg)"; cmp copia.tar.gpg copia2.tar.gpg | head -1