Termiyo

Segurança

Como o cofre funciona

Sem enrolação: aqui estão as construções de verdade, os parâmetros e por que cada um foi escolhido.

Contra o que estamos nos defendendo

Três situações moldam cada decisão abaixo. Um servidor de sincronização que guarda os seus dados e nunca deveria conseguir lê-los. Um notebook roubado, com o arquivo do banco de dados nas mãos de outra pessoa. E um atacante com esse arquivo offline, testando tentativas tão rápido quanto o hardware permitir.

A terceira é a que decide a derivação de chave, porque é a única em que o ritmo é dado pelo orçamento do atacante, e não pela sua senha.

Um segundo fator, e para que ele serve

O login em duas etapas protege a conta, não o cofre, e essa diferença importa mais do que parece. Uma senha roubada ou adivinhada deixa de bastar para conectar um aparelho novo e baixar as suas chaves seladas — o pacote cifrado e, porque essa mesma senha deriva a chave que o abre, tudo o que há dentro. É esse o ataque que um código realmente barra.

Ela continua bastando para abrir um cofre numa máquina que alguém já tem. O cofre é cifrado aqui, no seu próprio disco, sem nenhum servidor no meio a quem perguntar nada — então não há ali nada para um código guardar. A verificação em duas etapas também não desconecta aparelhos que já estão conectados, e não torna recuperável uma senha esquecida.

Ao ligar, o Termiyo mostra dez códigos de recuperação, uma única vez. Eles, e qualquer máquina ainda conectada — que pode desligar o fator com a sua senha —, são os dois caminhos de volta se o seu autenticador sumir. Não existe um terceiro: ninguém aqui pode deixar você passar por cima de um fator, porque do nosso lado não há nada que pudesse.

Argon2id, não um hash rápido

Sua senha mestra é esticada em uma chave de 32-byte com Argon2id a 64 MiB de memória e três passagens — o `crypto_pwhash` do libsodium, que roda o Argon2id em uma única pista. A memória é o ponto: uma GPU consegue rodar um número enorme de operações de hash em paralelo, mas não consegue dar 64 MiB de memória rápida para cada uma. Isso transforma um ataque paralelo largo de volta em um estreito.

Para comparar, uma derivação PBKDF2-SHA256 com mil iterações — ainda um padrão comum — custa ao atacante menos de um milissegundo por tentativa e paraleliza quase perfeitamente. O Argon2id com esses parâmetros leva cerca de 130 ms num notebook e resiste exatamente a esse paralelismo.

Os parâmetros ficam registrados junto ao cofre, então aumentá-los depois afeta as derivações novas enquanto os cofres existentes continuam abrindo.

Cada registro selado por conta própria

Cada cofre tem a própria chave aleatória de 32-byte, embrulhada sob a chave mestra. Os registros são cifrados com XChaCha20-Poly1305 usando um nonce novo de 24-byte, e a identidade do próprio registro — seu tipo, seu cofre e seu id — é amarrada como associated data.

Essa última parte importa mais do que parece. Sem ela, qualquer um com o texto cifrado poderia mover um bloco cifrado válido para outro registro e o cliente aceitaria. Com ela, um registro reetiquetado simplesmente não abre.

Compartilhar sem entregar uma chave

Cada conta tem um par de chaves X25519. Compartilhar um cofre sela a chave dele para a chave pública do destinatário, então um servidor pode administrar quem tem acesso a o quê sem nunca ter em mãos uma chave que abra algo.

Revogar o acesso remove a cópia selada e interrompe a sincronização. Isso não alcança o que a pessoa já tem: quem já leu os dados, leu, e nenhum sistema desfaz isso. Revogar também não muda a chave do cofre — o Termiyo não consegue —, então quem sincronizou enquanto tinha “Pode editar” fica com uma chave que abre tudo o que for salvo depois nesse cofre, onde quer que esses registros cheguem a ela; compartilhar o cofre de novo com essa pessoa, mesmo como “Somente leitura”, envia a ela pelo menos os hosts dele. O que recupera um segredo é trocar as senhas e as chaves nos próprios servidores.

Chaves de host, fixadas

Na primeira vez que o Termiyo vê um servidor, ele mostra a chave e sua impressão SHA-256, e fixa a que você aceitar. Cada reconexão é conferida contra essa fixação.

Quando uma chave muda, o Termiyo diz isso claramente em vez de esconder: um servidor reconstruído e uma conexão interceptada são idênticos para o software, e só você sabe qual dos dois estava esperando.

Onde os segredos realmente ficam

As conexões rodam em um processo separado da interface. A janela que desenha o seu terminal não tem acesso à rede nem ao sistema de arquivos, e nunca recebe uma senha ou uma chave privada — ela pede para conectar a um host salvo pelo nome, e outro processo decide o que isso significa.

Tudo que aparece na interface é mascarado antes. Salvar um registro de volta com um campo mascarado deixa o segredo armazenado intacto.

Conferir o que você baixou

Duas verificações diferentes, que respondem a perguntas diferentes. O SHA-256 ao lado de cada download na página de download diz que os bytes que você tem são os bytes que construímos: `shasum -a 256 <file>` no macOS e Linux, `certutil -hashfile <file> SHA256` no Windows.

A assinatura diz quem os construiu, e o seu sistema operacional a confere por você antes de rodar o aplicativo. Você pode conferir primeiro, por conta própria. No macOS: `spctl -a -t open --context context:primary-signature -vv <file>.dmg` deve responder "accepted" com "source=Notarized Developer ID".

O instalador do Windows não tem assinatura de código, por isso não há aba Assinaturas Digitais em Propriedades. A ausência dessa aba não permite saber se o arquivo foi alterado. Salve o instalador sem executá-lo e depois rode `certutil -hashfile "<file>" SHA256`, substituindo `<file>` pelo caminho do arquivo salvo. Compare o resultado com o SHA-256 ao lado desse mesmo download na página de download antes de abrir o instalador. Se forem diferentes, não o execute. Um hash igual confirma que os bytes correspondem ao nosso arquivo publicado; não é uma assinatura do publicador. Ao contrário do caso do Linux logo abaixo, isso é uma falha nossa e não uma propriedade da plataforma: o Windows confere assinaturas muito bem, o que falta é darmos a ele uma para conferir. Esta página vai continuar dizendo isso até que o instalador que você baixa carregue uma assinatura que você mesmo possa conferir.

No Linux não há equivalente — um .deb ou um AppImage não carrega assinatura que o seu sistema confira, então o hash é tudo o que você pode verificar. Isso é uma propriedade da plataforma, não uma escolha nossa, e é melhor saber do que supor o contrário.

O que sai da sua máquina

Duas coisas, e as duas estão listadas. O Termiyo envia um relatório curto sobre si mesmo no máximo uma vez a cada 24 horas — versão, plataforma, processador, como foi instalado, idioma da interface, se a verificação de atualizações está ligada e uma contagem dos despejos de falha que estão na pasta dele — sem identificador nenhum e sem nada das suas sessões dentro; está ligado por padrão e desliga com um clique, na primeira execução ou em Configurações → Ajuda. Uma falha escreve um dump numa pasta do seu próprio disco, e enviar um desses para nós é uma chave separada que fica desligada até você ligá-la; Configurações → Ajuda mostra qual é, diz o que um dump pode conter, e abre a pasta.

Enviar um para nós é uma chave naquela tela. Ela está desligada numa instalação nova, desligada depois de uma atualização, e enquanto estiver desligada nenhum dump sai da máquina: anexá-lo à mão a um relatório de erro continua sendo o único jeito de ele viajar. Ligue-a: se “Verificar atualizações quando o Termiyo iniciar” estiver ligado, a próxima falha enviará o dump por HTTPS, junto com o nome que a sua própria máquina deu àquele arquivo, a versão, a plataforma, a arquitetura do processador e um identificador daquela instalação criado nesse primeiro envio, e mais nada; a mesma tela lista o que foi enviado e tem um botão que pede ao nosso servidor para apagar. Este parágrafo dizia antes que o envio de relatórios de falha era ausente e não apenas desligado, o que era verdade em todas as versões anteriores à que acrescentou o endereço. A página de privacidade tem o detalhe. Com a verificação de atualizações desligada, um dump que você aceitou enviar espera nesta máquina e sai na primeira inicialização depois que ela for ligada de novo.

Com a verificação de atualizações desligada, o atualizador nunca é carregado: a biblioteca é importada no primeiro uso, então com a verificação desligada o módulo nunca é importado e não tem com o que fazer uma requisição. Isso é estrutural, e não uma promessa sobre um trecho de código.

O que dissemos errado aqui, e estamos corrigindo: este texto afirmava que, com a verificação desligada, uma inicialização não faz nenhuma requisição para fora, e oferecia o tcpdump como a forma de conferir isso. Uma inicialização em que ninguém mexe agora fica mesmo em silêncio com a verificação desligada — medido na rede, no Linux —, mas abrir o cofre começa um tráfego que não tem nada a ver com a configuração de atualizações, e esta página só citava parte dele. O primeiro são os terminais que você deixou abertos: as abas SSH que ainda estavam abertas quando o Termiyo foi fechado pela última vez são reabertas assim que o cofre abre, cada uma com um login completo no host — é isso que devolve o seu trabalho ao ponto onde você parou, e uma aba que você fecha antes de sair não volta sozinha. Sem login, até você responder à oferta de uma conta, a tela de primeira execução pergunta se o termiyo.com responde, para saber se vale a pena oferecer uma conta a você — uma vez por inicialização, no primeiro desbloqueio; enquanto o termiyo.com não pode ser alcançado a oferta não aparece, então a próxima inicialização pergunta de novo. Com login, o Termiyo pergunta se o seu endereço já foi confirmado — uma vez por inicialização, e mais uma vez enquanto não estiver, porque o painel que então pede o seu código lê a resposta de novo —, sincroniza quando o cofre abre e a cada cinco minutos depois disso, pergunta em qual dos seus cofres um host, um grupo ou um proxy pode ser salvo quando você abre o formulário dele, e, se você não tem uma chave de IA própria, pergunta quanto resta da cota de IA da sua conta quando você abre o painel de IA ou começa a digitar em um terminal. Enquanto a lista de hosts está aberta, cada host SSH ou telnet salvo que o Termiyo consegue alcançar diretamente é verificado a cada 15 segundos — uma conexão à porta dele, fechada sem enviar um único byte — para que o ponto ao lado esteja em dia; essas conexões vão para os seus servidores, não para nós, e aparecem nos logs deles. Um host salvo pelo nome, e não pelo endereço, custa além disso uma consulta de DNS a cada vez, e ela vai para o resolvedor que a sua máquina usa. Esconder a lista de hosts interrompe essas verificações, mas não outra do mesmo tipo: enquanto a aba da frente for um terminal conectado a um desses hosts, a barra de status verifica esse host a cada 10 segundos para a latência que mostra, com lista ou sem ela, enquanto a barra mostrar “Conectado”, e, para um host salvo pelo nome, também consulta o seu resolvedor sobre ele a cada vez. E o que você configurou faz aquilo para que foi configurado: um backup agendado se copia para o espelho que você indicou, os webhooks chamam os seus endereços, e as tarefas agendadas e os redirecionamentos se conectam aos seus hosts — uma tarefa agendada uma vez por execução, saindo da sessão quando o snippet termina. Então a afirmação estava errada justamente na forma que dissemos ser a que vale a pena, a que se pode conferir.

Um terminal que você compartilha é um segundo lugar onde a sessão existe, e esse segundo lugar é uma aba de navegador. Os bytes vão da sua máquina para a da outra pessoa e não passam por mais nada: nenhum relay os carrega, e isso é uma escolha — um servidor TURN veria o tráfego, então o Termiyo não usa nenhum, e o nosso próprio servidor só apresenta vocês dois um ao outro. O que usamos é STUN público, o do Google e o da Cloudflare, para perguntar como o seu endereço aparece de fora; esses dois ficam sabendo esse endereço, e nada mais. O navegador do convidado não recebe nenhum servidor STUN. Depois vem o custo: o convidado está assistindo em um navegador, então extensões conseguem ler aquela página e o navegador pode guardar uma imagem dela para a pré-visualização da aba. O convidado começa em somente leitura e não consegue digitar até você permitir, e o compartilhamento termina quando você para de compartilhar, ou depois de quatro horas. O que isso não é: a mesma proteção que o próprio aplicativo dá — e a página do convidado diz isso na tela do próprio convidado, não só aqui.

O que não podemos afirmar: o arquivo SQLite em si não é cifrado, só os registros dentro dele. Quem tiver o arquivo descobre quantos servidores você tem, quando tocou em cada um pela última vez e os nomes que você deu a eles. Os endereços, usuários, senhas e chaves estão cifrados. Preferimos dizer isso aqui do que você descobrir.

Achou algo?

Relatos de segurança vão para info@termiyo.com. Confirmamos o recebimento em dois dias úteis.