Atualizado

Criptografia de conhecimento zero: como o Vaulted mantém seus segredos privados

Por

A criptografia de conhecimento zero significa que o servidor nunca vê seus dados em texto puro nem suas chaves de criptografia. O Vaulted implementa isso criptografando cada segredo no seu navegador com AES-256-GCM antes que qualquer dado chegue ao servidor. O servidor armazena apenas o texto cifrado — ele nunca tem acesso à chave de descriptografia, que vive exclusivamente no fragmento da URL.

Este artigo percorre a implementação criptográfica exata: como as chaves são geradas, como os dados são criptografados, como a chave chega ao destinatário e o que acontece quando você adiciona uma frase secreta. Cada detalhe aqui reflete o código real que roda no seu navegador.

Para uma visão geral de por que a criptografia do lado do cliente importa, confira nosso artigo anterior sobre criptografia do lado do cliente. Este artigo aprofunda nas primitivas criptográficas.

Geração de chaves

Toda vez que você cria um segredo, o Vaulted gera uma chave de criptografia AES-256-GCM nova usando a Web Crypto API:

crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
  'encrypt',
  'decrypt',
]);

Alguns pontos a observar:

  • AES-GCM (Galois/Counter Mode) oferece tanto confidencialidade quanto integridade — ele detecta adulterações, não apenas a leitura não autorizada.
  • O comprimento de chave de 256 bits é a opção mais robusta disponível para AES e é usado por governos e instituições financeiras no mundo todo.
  • Extractable: true — a chave pode ser exportada como bytes brutos para que possa ser colocada no fragmento da URL destinado ao destinatário.

A Web Crypto API delega ao mecanismo criptográfico nativo do navegador (por exemplo, BoringSSL no Chromium, NSS no Firefox). A chave é gerada de forma segura na memória e nunca toca o disco nem a rede.

Criptografia

Com a chave gerada, o Vaulted criptografa seu texto puro:

const iv = crypto.getRandomValues(new Uint8Array(12));

crypto.subtle.encrypt(
  { name: 'AES-GCM', iv },
  key,
  new TextEncoder().encode(plaintext),
);

O vetor de inicialização (IV): o AES-GCM exige um IV aleatório de 12 bytes (96 bits) para cada operação de criptografia. O IV não precisa ser secreto — ele é armazenado junto com o texto cifrado —, mas nunca deve ser reutilizado com a mesma chave. Como o Vaulted gera uma chave nova para cada segredo, a reutilização do IV é impossível por design.

Codificação: tanto o texto cifrado quanto o IV são codificados como strings base64url (base64 padrão com + substituído por -, / substituído por _ e os = finais removidos). Isso os torna seguros para serem incluídos em URLs e payloads JSON.

O texto cifrado e o IV são enviados ao servidor para armazenamento. O texto puro nunca sai do navegador.

Entrega da chave no fragmento da URL

Após a criptografia, a chave é exportada e colocada no fragmento da URL — a parte depois do #:

const rawKey = await crypto.subtle.exportKey('raw', key);
// rawKey → base64url-encoded string

O link de compartilhamento resultante tem esta aparência:

https://vaulted.fyi/s/abc123#dGhpcyBpcyBhIGtleQ
                              ^^^^^^^^^^^^^^^^^^^^^^^^
                              encryption key (base64url)

O separador # é fundamental. De acordo com a RFC 3986, o identificador de fragmento é processado inteiramente pelo cliente. Os navegadores nunca incluem o fragmento nas requisições HTTP — nem na URL, nem no cabeçalho Referer, nem em qualquer lugar que o servidor possa ver.

Quando o destinatário abre o link:

  1. O navegador solicita /s/abc123 ao servidor (sem o fragmento)
  2. O servidor retorna o texto cifrado e o IV
  3. O JavaScript lê o fragmento a partir de window.location.hash
  4. A chave é importada de volta para a Web Crypto API
  5. O texto cifrado é descriptografado localmente

O servidor facilita o armazenamento e a recuperação do bloco criptografado. Ele nunca participa das operações criptográficas.

Proteção opcional com frase secreta

Para os segredos que precisam de proteção adicional, o Vaulted oferece suporte ao encapsulamento de chave baseado em frase secreta. Isso adiciona uma segunda camada: mesmo que alguém intercepte o link, não conseguirá descriptografar o segredo sem a frase secreta.

Derivação de chave com PBKDF2

Quando você define uma frase secreta, o Vaulted deriva uma chave de encapsulamento usando PBKDF2:

crypto.subtle.deriveKey(
  {
    name: 'PBKDF2',
    salt, // 16 bytes, randomly generated
    iterations: 600_000,
    hash: 'SHA-256',
  },
  keyMaterial, // the passphrase, imported as raw key material
  { name: 'AES-KW', length: 256 },
  false,
  ['wrapKey', 'unwrapKey'],
);
  • 600.000 iterações tornam os ataques de força bruta computacionalmente caros.
  • Um salt aleatório de 16 bytes garante que frases secretas idênticas produzam chaves derivadas diferentes em segredos diferentes.
  • SHA-256 é a função de hash usada em cada iteração do PBKDF2.
  • A chave derivada é uma chave AES-KW (AES Key Wrap, RFC 3394), não uma chave AES-GCM. O encapsulamento de chave é uma operação distinta da criptografia.

Encapsulamento da chave de criptografia

A chave AES-KW derivada encapsula a chave de criptografia original:

crypto.subtle.wrapKey('raw', encryptionKey, wrappingKey, 'AES-KW');

O fragmento da URL agora contém tanto a chave encapsulada quanto o salt, separados por um ponto:

#wrappedKeyBase64url.saltBase64url

Desencapsulamento na descriptografia

Quando o destinatário insere a frase secreta, o Vaulted inverte o processo:

  1. Divide o fragmento no . para obter a chave encapsulada e o salt
  2. Deriva a mesma chave de encapsulamento AES-KW usando PBKDF2 com a frase secreta e o salt
  3. Desencapsula a chave de criptografia com crypto.subtle.unwrapKey
  4. Descriptografa o texto cifrado com a chave AES-GCM desencapsulada

Se a frase secreta estiver errada, o unwrapKey lança um erro — não há descriptografia parcial nem vazamento de informação.

Fluxo de descriptografia

Sem uma frase secreta, a descriptografia é direta:

  1. Importa a chave a partir do fragmento da URL (crypto.subtle.importKey)
  2. Descriptografa o texto cifrado com o IV (crypto.subtle.decrypt)
  3. Decodifica o texto puro a partir dos bytes UTF-8

Com uma frase secreta:

  1. Divide o fragmento para extrair a chave encapsulada e o salt
  2. Deriva a chave de encapsulamento a partir da frase secreta e do salt (PBKDF2)
  3. Desencapsula a chave de criptografia (AES-KW)
  4. Descriptografa o texto cifrado (AES-GCM)
  5. Decodifica o texto puro

Tudo isso acontece no navegador. O servidor retorna o bloco criptografado e os metadados (contagem de visualizações, expiração) — nada mais.

Modelo de ameaças

Nenhuma ferramenta de segurança protege contra tudo. Veja o que a arquitetura do Vaulted foi projetada para tratar e o que fica fora de seu escopo.

Contra o que o Vaulted protege

  • Comprometimento do servidor — o servidor armazena apenas o texto cifrado. Sem a chave (que nunca é enviada ao servidor), os dados são ilegíveis. Um dump completo do banco de dados rende apenas blocos criptografados.
  • Vazamento do banco de dados — o mesmo que acima. O texto cifrado sem chaves é computacionalmente inútil com AES-256-GCM.
  • Ataque man-in-the-middle do lado do servidor — a chave de criptografia vive no fragmento da URL, que nunca é transmitido nas requisições HTTP. O TLS protege o texto cifrado em trânsito.
  • Operadores do serviço lendo segredos — conhecimento zero significa exatamente isso. Não conseguimos ler seus segredos mesmo que fôssemos obrigados a isso, porque não temos as chaves.

Contra o que o Vaulted NÃO protege

  • Navegador ou dispositivo comprometido — se o dispositivo do destinatário tiver malware ou um keylogger, o texto puro descriptografado pode ser capturado após a descriptografia.
  • Extensões de navegador maliciosas — extensões com acesso à página podem ler o DOM após a descriptografia, incluindo o segredo revelado.
  • Interceptação do link — a URL contém a chave de criptografia no fragmento. Qualquer pessoa que obtenha a URL completa (incluindo o fragmento) pode descriptografar o segredo. Compartilhe os links por canais seguros.
  • Espionagem por cima do ombro — assim que o segredo é exibido na tela, qualquer pessoa que estiver olhando pode vê-lo.
  • Comportamento do destinatário — após a descriptografia, o destinatário pode tirar uma captura de tela, copiar ou compartilhar o texto puro. O Vaulted não consegue impedir isso.

O recurso de frase secreta mitiga a interceptação do link: mesmo com a URL completa, o atacante ainda precisa da frase secreta. Compartilhe a frase secreta por um canal diferente (uma ligação telefônica, uma mensagem à parte) para uma defesa em profundidade.

Resumo

A criptografia de conhecimento zero do Vaulted significa:

  1. Uma chave AES-256-GCM nova é gerada para cada segredo
  2. A criptografia acontece inteiramente no seu navegador
  3. O servidor armazena apenas o texto cifrado
  4. A chave de descriptografia viaja somente no fragmento da URL, que os navegadores nunca enviam aos servidores
  5. O encapsulamento opcional com frase secreta adiciona uma segunda camada via PBKDF2 e AES-KW

O resultado: mesmo que todos os servidores, bancos de dados e caminhos de rede fossem comprometidos simultaneamente, seus segredos permaneceriam criptografados. As chaves existem apenas nos links que você compartilha.


Tudo pronto para compartilhar um segredo de forma segura? Crie um segredo no Vaulted — leva 10 segundos.


Relacionado