Pass — Gestor de Contraseñas

pass, el gestor de contraseñas estándar de Unix: instalación, creación de la clave GPG, inicialización del almacén y sincronización con Git.

Introducción

Durante años usé una hoja de cálculo cifrada como gestor de contraseñas improvisado. Nunca quise recurrir a un servicio de terceros, porque delegar el almacenamiento de mis credenciales en una infraestructura ajena implica renunciar a la soberanía sobre ellas. Aun así, pospuse demasiado tiempo la migración a un sistema más consistente, más seguro y capaz de sincronizarse entre varios dispositivos.

El problema con KeePass

Mi primera opción fue KeePass: un formato abierto, auditado y con un ecosistema amplio de clientes. Sin embargo, tiene una limitación que me resultaba incómoda. La base de datos KDBX es un único contenedor cifrado de forma monolítica, de modo que cualquier modificación, por pequeña que sea, produce un archivo completamente distinto a nivel de bytes.

Eso tiene dos consecuencias. La primera es que, como el texto cifrado tiene una entropía prácticamente máxima, un sistema de control de versiones no puede calcular diferencias útiles entre revisiones y termina guardando una copia íntegra del archivo en cada commit. La segunda es que los cambios concurrentes desde dos dispositivos no se pueden fusionar: generan conflictos que hay que resolver a mano.

Por qué pass

Finalmente encontré pass, el gestor de contraseñas estándar de Unix, cuyo diseño me pareció especialmente elegante. Cada entrada es un archivo independiente cifrado con GPG dentro de una jerarquía de directorios, y la herramienta integra Git de forma nativa (pass git ...). Frente a un contenedor monolítico, las ventajas son varias:

  • Historial legible. Los cambios quedan aislados por entrada, así que el historial refleja exactamente qué credencial se modificó y cuándo.
  • Menos conflictos. Las ediciones simultáneas en entradas distintas se fusionan sin intervención.
  • Sincronización trivial. Se reduce a un push y un pull contra un repositorio remoto, que puede alojarse en un servidor propio, que es lo que hice.
  • Criptografía asimétrica. La seguridad descansa en claves GPG y la clave privada nunca necesita salir de los dispositivos del usuario.
  • Cliente para Android. Password Store trabaja contra el mismo repositorio y las mismas claves.

Instalar pass

En Debian y derivadas:

sudo apt install pass

En macOS, teniendo MacPorts instalado:

sudo port install pass

Claves GPG

pass no implementa criptografía propia: delega el cifrado en GPG (GNU Privacy Guard), que trabaja con criptografía asimétrica, es decir, con un par de claves pública/privada. La pública cifra cada entrada y la privada la descifra. Además, la clave privada se guarda cifrada con una passphrase, lo que añade un nivel extra de protección si alguien llega a tener acceso al disco.

Dónde se guardan

GPG mantiene todo su material en:

~/.gnupg/

Organizado de la siguiente manera:

~/.gnupg/
├── pubring.kbx               # Claves públicas (propias e importadas)
├── trustdb.gpg               # Nivel de confianza asignado a cada clave
├── private-keys-v1.d/        # Claves privadas, una por archivo
│   ├── A1B2C3...F9.key
│   └── D4E5F6...07.key
├── openpgp-revocs.d/         # Certificados de revocación
│   └── <FINGERPRINT>.rev
├── gpg.conf                  # Configuración de gpg
└── gpg-agent.conf            # Configuración de gpg-agent
  • pubring.kbx: contiene todas las claves públicas, tanto las propias como las importadas de otras personas, junto con sus identidades (nombre y correo), subclaves y firmas.
  • private-keys-v1.d/: guarda las claves privadas. Cada clave y cada subclave es un archivo independiente, nombrado por su keygrip. Están cifrados con la passphrase y los gestiona gpg-agent.
  • trustdb.gpg: almacena cuánto se confía en cada clave pública, es decir, si se cree que realmente pertenece a quien dice ser.
  • openpgp-revocs.d/: contiene un certificado de revocación por cada clave generada. Sirve para invalidar la clave si se pierde o queda comprometida.
  • gpg.conf y gpg-agent.conf: archivos de configuración opcionales, por ejemplo para definir algoritmos preferidos o cuánto tiempo se recuerda la passphrase.

Para ver qué claves hay y qué archivo corresponde a cada una:

gpg --list-keys                              # claves públicas
gpg --list-secret-keys --with-keygrip        # claves privadas y su keygrip

Cómo se identifican

Las claves se quedan en la carpeta personal del usuario, pero hay que referirse a ellas constantemente desde la línea de comandos. Para eso existen cuatro identificadores: el fingerprint, el key ID, el keygrip y el User ID.

  • Fingerprint (huella digital): es el identificador principal y único de la clave, un hash del material público de 40 caracteres hexadecimales (SHA-1) en claves v4 o de 64 (SHA-256) en claves v6. Por ejemplo: 3A1F 9C2E 7B4D 0A11 8E6C 5F2B 9D03 47AA C1E8 B205. Es la forma más segura de referirse a una clave.
  • Key ID: es el final del fingerprint. El long key ID son los últimos 16 caracteres (9D0347AAC1E8B205) y el short key ID, los últimos 8 (C1E8B205). El corto ya no se considera seguro, porque es fácil fabricar claves falsas que coincidan con él.
  • Keygrip: es un identificador interno que usa gpg-agent y que da nombre a los archivos de private-keys-v1.d/. A diferencia del fingerprint, solo depende del material criptográfico de la clave, no del formato OpenPGP.
  • User ID: es la identidad legible asociada a la clave, con la forma Nombre (comentario) <email>. Resulta cómodo en comandos como pass init usuario@ejemplo.com, pero no es único: cualquiera puede crear una clave con el nombre y el correo de otra persona.

Para ver todos estos identificadores a la vez:

gpg --list-keys --keyid-format long --with-fingerprint --with-keygrip

Crear la clave

El par de claves se genera en modo interactivo:

gpg --full-generate-key

GPG pregunta por cada detalle de la clave. A continuación, qué responder en cada paso.

1. Tipo de clave

gpg: directory '/Users/mac/.gnupg' created
Please select what kind of key you want:
   (1) RSA and RSA
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (sign only)
  (14) Existing key from card
  (16) ECC and Kyber
Your selection?

Elegí el tipo 9, que es el valor por defecto. ECC (Elliptic Curve Cryptography) genera una clave primaria de firma y certificación basada en EdDSA (Ed25519) y una subclave de cifrado basada en ECDH (Cv25519). Frente a RSA ofrece un nivel de seguridad equivalente con claves mucho más cortas (256 bits en ECC equivalen aproximadamente a 3072 bits en RSA), lo que se traduce en firmas más pequeñas y operaciones más rápidas.

2. Curva elíptica

Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection?

Elegí la opción 1, Curve 25519, que es la recomendada: está diseñada para resistir ataques de canal lateral (implementaciones de tiempo constante), no depende de constantes de origen opaco como las curvas NIST y está ampliamente soportada en GnuPG >= 2.1.

3. Periodo de validez

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)

Indiqué 0, es decir, sin vencimiento: no creo que lo necesite para este tipo de clave.

4. User ID

GnuPG needs to construct a user ID to identify your key.

Real name: Nombre Apellido
Email address: usuario@ejemplo.com
Comment:
You selected this USER-ID:
    "Nombre Apellido <usuario@ejemplo.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

El campo Comment es opcional y conviene dejarlo vacío, por tres razones:

  • Forma parte del User ID, que queda ligado criptográficamente a la clave mediante la autofirma (self-signature) y por tanto no se puede editar. Para cambiarlo hay que crear un UID nuevo y revocar el anterior, y el UID revocado queda visible en los keyservers y en las copias de la clave pública que tengan otras personas.
  • Puede causar problemas de compatibilidad con herramientas que esperan el formato Nombre <email> y no Nombre (comentario) <email>.
  • Debilita la Web of Trust: quien certifica un UID no puede verificar el contenido del comentario, así que muchos usuarios evitan firmar los UID que lo incluyen.

5. Passphrase

Por último se pide la passphrase con la que se cifrará la clave privada en disco, en ~/.gnupg/private-keys-v1.d/. Para generarla uso el propio gpg, que devuelve 32 bytes aleatorios codificados en base64:

gpg --gen-random --armor 2 32

Resultado

Al terminar, GnuPG muestra un resumen parecido a este:

gpg: revocation certificate stored as '/Users/mac/.gnupg/openpgp-revocs.d/<FINGERPRINT>.rev'
public and secret key created and signed.

pub   ed25519 2026-10-11 [SC]
      <FINGERPRINT>
uid                      Nombre Apellido <usuario@ejemplo.com>
sub   cv25519 2026-10-11 [E]

[SC] indica que la clave primaria sirve para firmar (Sign) y certificar (Certify), y [E], que la subclave se usa para cifrar (Encrypt). No aparece ningún [expires: ...] porque la clave se creó sin fecha de vencimiento.

El certificado de revocación que GPG genera automáticamente conviene copiarlo a un lugar seguro fuera del equipo: es lo único que permite invalidar la clave si se pierde o queda comprometida.

Iniciar el almacén

Con la clave ya creada se puede inicializar el almacén de contraseñas, que vive en ~/.password-store (o en la ruta que indique la variable PASSWORD_STORE_DIR). Hay que pasarle el identificador de la clave con la que se cifrarán las entradas:

pass init <GPG-ID>

Esto crea el archivo ~/.password-store/.gpg-id, que guarda el identificador de la clave usada para cifrar cada entrada.

Sirve cualquiera de los cuatro identificadores:

pass init 3A1F9C2E7B4D0A118E6C5F2B9D0347AAC1E8B205   # fingerprint
pass init 9D0347AAC1E8B205                           # long ID
pass init C1E8B205                                   # short ID
pass init usuario@ejemplo.com                        # email / UID

Lo recomendable es usar el fingerprint completo, para evitar colisiones con otras claves, por ejemplo si dos comparten el mismo UID. Los short ID son especialmente problemáticos: con solo 32 bits, fabricar una clave que coincida con uno es trivial, un ataque conocido como Evil32.

Versionar el almacén con Git

Opcionalmente, el almacén se puede versionar con Git:

pass git init

Desde ese momento, pass crea un commit automático cada vez que se modifica el almacén. Para sincronizar basta añadir un remoto:

pass git remote add origin git@servidor:usuario/password-store.git
pass git push -u origin main

El nombre de la rama depende de la configuración init.defaultBranch de Git; en instalaciones antiguas será master.

A partir de ahí, la sincronización es la de cualquier repositorio:

pass git pull
pass git push

Cualquier subcomando de Git funciona anteponiendo pass git, ya que pass lo ejecuta dentro de ~/.password-store.

Como los archivos .gpg van cifrados, el remoto solo almacena texto cifrado. Aun así, los nombres de las entradas, que son las rutas de los archivos, quedan visibles en claro, así que conviene usar un repositorio privado.

Pass commands

Cada entrada se referencia por su ruta relativa a ~/.password-store, sin la extensión .gpg: pass show correo/trabajo descifra ~/.password-store/correo/trabajo.gpg. Los directorios son la única jerarquía que existe, así que basta con nombrar las entradas con barras para organizarlas. Si el almacén está versionado, todos los comandos que lo modifican crean su propio commit.

Listar y buscar

pass                        # muestra el árbol completo del almacén
pass ls correo              # muestra solo un subdirectorio
pass find trabajo           # busca en los nombres de las entradas
pass grep "ejemplo.com"     # busca dentro del contenido descifrado

find (alias search) solo mira los nombres de las entradas, que están en claro, así que es inmediato. grep descifra todas las entradas una por una para buscar en su contenido, por lo que pide la passphrase y tarda bastante más.

Ver una contraseña

pass show correo/trabajo    # imprime la entrada completa en el terminal
pass correo/trabajo         # show es el subcomando por defecto
pass -c correo/trabajo      # copia la contraseña al portapapeles
pass -c3 correo/trabajo     # copia la línea 3 en lugar de la primera
pass -q correo/trabajo      # muestra la contraseña como código QR

Con -c la contraseña no aparece nunca en pantalla y el portapapeles se limpia automáticamente a los 45 segundos (PASSWORD_STORE_CLIP_TIME). El código QR de -q necesita qrencode instalado y resulta cómodo para pasar una credencial al móvil.

Añadir entradas

pass insert correo/trabajo         # pide la contraseña dos veces, sin eco
pass insert -e correo/trabajo      # la pide una sola vez, mostrándola
pass insert -m correo/trabajo      # lee varias líneas hasta Ctrl-D
pass insert -f correo/trabajo      # sobrescribe sin preguntar

Por convención, la primera línea es la contraseña y el resto son metadatos de formato libre. Es lo que esperan pass -c, pass generate -i y los clientes como Password Store o Browserpass:

contraseña-super-secreta
user: mac
url: https://ejemplo.com

Generar contraseñas

pass generate correo/trabajo         # 25 caracteres, con símbolos
pass generate correo/trabajo 40      # longitud explícita
pass generate -n correo/trabajo      # solo alfanuméricos, sin símbolos
pass generate -c correo/trabajo      # además copia al portapapeles
pass generate -i correo/trabajo      # reemplaza solo la primera línea

La longitud por defecto es de 25 caracteres y se puede cambiar con PASSWORD_STORE_GENERATED_LENGTH. La opción -i (--in-place) es la que conviene al rotar una contraseña: sustituye la primera línea y conserva intactos los metadatos. Sin -i ni -f, pass pregunta antes de sobrescribir una entrada que ya existe.

Editar, mover y borrar

pass edit correo/trabajo                   # abre la entrada en $EDITOR
pass mv correo/trabajo trabajo/correo      # renombra o mueve
pass cp correo/trabajo correo/respaldo     # duplica
pass rm correo/trabajo                     # borra una entrada
pass rm -r correo                          # borra un directorio completo

pass edit descifra la entrada en un archivo temporal, lanza $EDITOR y la vuelve a cifrar al guardar. En Linux ese temporal se crea en /dev/shm, es decir, en memoria; en macOS, que no tiene /dev/shm, pass advierte de que el archivo en claro quedará en disco y pide confirmación antes de continuar.

mv y cp vuelven a cifrar la entrada cuando el destino está bajo un .gpg-id distinto, por ejemplo en un subdirectorio compartido con otras claves.

Variables de entorno

  • PASSWORD_STORE_DIR: ubicación del almacén. Por defecto, ~/.password-store.
  • PASSWORD_STORE_CLIP_TIME: segundos que la contraseña permanece en el portapapeles al usar -c. Por defecto, 45.
  • PASSWORD_STORE_GENERATED_LENGTH: longitud por defecto de pass generate. Por defecto, 25.
  • PASSWORD_STORE_UMASK: permisos con los que se crean los archivos del almacén.

Referencia completa

Los subcomandos de Git ya quedaron descritos en la sección anterior. Para el resto de opciones:

pass help
man pass