Edit page

Segurança e Criptografia

Mecanismos Básicos de Comunicação Segura

Iremos abordar como é possível comunicar com outra entidade de forma segura, garantindo que não existem intrusos a intercetar a conversa, a modificar o conteúdo das mensagens ou a fazer-se passar por um de nós.

Algumas notas prévias:

  • Iremos designar por AA e BB as entidades que pretendem estabelecer um canal seguro (tipicamente designadas por "Alice" e "Bob")
  • Uma entidade que queira escutar ou perturbar a comunicação será designada por TT (tipicamente designada por "Trudy", de "intruder")

Vamos estudar de seguida mecanismos básicos utilizados para tornar um canal seguro.

Chaves simétricas

No contexto de uso de uma chave simétrica existe:

  • uma chave secreta KSK_S conhecida por AA e BB
  • um texto mm (plaintext)
  • uma função de cifra que produz um texto cifrado (ciphertext) a partir de mm e KSK_S, designada KS(m)K_S(m)
    • NOTA: a chave em si não cifra a mensagem, esta é utilizada por um algoritmo
  • uma função para decifrar o texto cifrado que usa a mesma chave: m=KS(KS(m))m = K_S(K_S(m))

Uso de chave simétrica

Podemos nestas condições criar um canal seguro entre AA e BB desde que estes conheçam previamente a chave, mas como é que a distribuição da chave é feita? Por exemplo, pode ser trocada fisicamente ou então derivada de uma palavra chave combinada previamente.

Existem dois grandes problemas com o uso desta chave:

  • Como podemos ter a certeza de que estamos de facto a ler o que foi enviado pela outra entidade?
  • Um intruso TT pode simplesmente escutar o que AA envia para BB e reenviar exatamente a mesma mensagem a BB (fazendo com que BB execute uma transferência bancária duas vezes por exemplo)

Fatores que influenciam a segurança da chave

A segurança depende não só do algoritmo de cifra usado como também do tamanho da própria chave (nº bits) e do poder computacional do adversário.

Chaves assimétricas

Agora em vez de termos apenas uma chave partilhada, cada entidade passa a possuir um par de chaves (K+K_+, KK_-), designadas por chave pública e privada, respectivamente. Estas chaves apresentam as seguintes propriedades:

  • a chave pública K+K_+ é partilhada com as outras entidades
  • a chave privada KK_- é mantida secreta
  • K+(K(m))=mK_+(K_-(m)) = m
  • K(K+(m))=mK_-(K_+(m)) = m
  • não é possível obter uma chave a partir da outra

A utilização destas chaves permite que, ao enviarmos uma mensagem para BB, se a encriptarmos com a chave KB+K_{B+}, somente BB, com a sua chave privada KBK_{B-}, será capaz de decifrá-la. Para além disso, se AA desejar provar a BB que o texto mm foi produzido por si, basta encriptar mm com KAK_{A-} e BB decifrar com KA+K_{A+}. Se for bem sucedido, então mm foi garantidamente enviado por AA, já que apenas este conhece KAK_{A-}.

Uso de chave assimétrica

O uso destas chaves tem no entanto uma grande desvantagem: a criptografia assimétrica é muito mais lenta do que a simétrica (100 a 1000 vezes). Por este motivo, é muito comum utilizar esta criptografia para negociar uma chave simétrica durante a criação do canal seguro (de forma a garantir que estamos a comunicar com a entidade certa), que será posteriormente utilizada na encriptação de toda a comunicação (método conhecido como "chave mista"). Exemplo:

  1. AA cria uma chave simétrica KSK_S e cifra-a com KB+K_{B+}
  2. Apenas BB consegue obter KSK_S já que é o único que possui KBK_{B-}

Perigo de divulgar a chave pública

Apesar da divulgação da chave pública parecer fácil visto que pode ser partilhada, tem um perigo associado: intruso em chave assimétrica

Este ataque é conhecido como "Men-in-the-middle attack", onde o atacante reencaminha (e possivelmente altera) secretamente as comunicações entre duas entidades que acreditam estar a comunicar diretamente uma com a outra.

Criptografia RSA

Já abordámos em EMD um algoritmo de criptografia assimétrica, o RSA.

Funções de Hash Criptográficas

De forma a conseguirmos ter a garantia que estamos a ler o que foi enviado pelo remetente, podemos utilizar uma função de hash e enviar o hash do texto (também conhecido como "digest") juntamente com o mesmo.

Dado um texto mm, uma função de hash criptográfica cria um hash de tamanho fixo H(m)H(m). Estas funções apresentam uma propriedade fundamental que é ser computacionalmente inviável encontrar em tempo útil outro texto mm' tal que H(m)=H(m)H(m') = H(m), ou seja, em termos práticos é impossível modificar o texto de forma a que tenha o mesmo hash que o original.

Para aumentar ainda mais a segurança do hash, podemos calculá-lo a partir do texto e da chave privada (simétrica), em vez de apenas do texto.

Nonce

Um nonce é uma palavra chave única que é utilizada para identificar uma troca de mensagens e que não é usada novamente em comunicações posteriores.

Utilização de nonce

O objetivo da utilização do nonce é eliminar uma vulnerabilidade mencionada anteriormente: um atacante pode simplesmente repetir as mensagens cifradas (problema conhecido como "replay attack"). Ao utilizar uma palavra chave única por comunicação, caso um atacante repita as mensagens posteriormente, estas serão ignoradas pelo destinatário, pois este sabe que se tratam de mensagens repetidas.

O cálculo de um nonce é tipicamente baseado numa das seguintes técnicas (ou na sua combinação):

  • timestamps (segurança dependente da segurança do relógio da máquina)
  • números de sequência monotonicamente crescentes (segurança dependente da capacidade das máquinas memorizarem o último número usado)

Os nonces também podem ser utilizados para garantir que estamos a falar com a entidade certa:

  • encriptamos o nonce com uma chave
  • esperamos que a outra entidade devolva uma versão modificada (determinista) do nonce enviado (por exemplo, nonce + 1)
  • como apenas a outra entidade detém a chave de forma a decifrar o que enviamos, apenas esta consegue ler o nonce enviado e modificá-lo como combinado

Confirmação de identidade com nonce

Mecanismos Avançados de Comunicação Segura

Combinando todos os mecanismos abordados até agora, podemos obter outros mais sofisticados, como por exemplo:

  • Assinaturas digitais
  • Infra-estruturas de chaves públicas e certificados
  • Troca segura de e-mails
  • Canais seguros
  • Sistemas de autenticação com "single sign-on"

Assinaturas Digitais com Chave Simétrica

AA e BB partilham uma chave KSK_S e AA quer assinar um texto mm de forma a que BB possa confirmar que mm foi gerado por AA (autenticidade) e que não foi alterado durante o percurso (integridade). Para tal:

  • AA cria uma versão estendida do texto (mKSm|K_S), concatenando ao texto mm o segredo KSK_S
  • AA usa uma função de hash criptográfica para gerar o digest da versão estendida Sm=H(mKS)S_m = H(m|K_S)
  • AA envia ambos a BB
  • BB verifica se Sm=H(mKS)S_m = H(m|K_S)

Este tipo de assinatura apenas pode ser usado entre duas entidades que partilham um segredo e é tipicamente designado por Message Authentication Code (MAC)

Assinaturas Digitais com Chave Assimétrica

AA tem KAK_{A-} e BB conhece KA+K_{A+} (veremos como é que isto é possível com certificados). AA quer assinar um texto mm de forma a que BB possa confirmar a sua autenticidade e integridade, e que também consiga provar a outro que a mensagem mm foi de facto enviada por AA (não repúdio). Para tal:

  • AA usa uma função de hash criptográfica para gerar o digest da mensagem H(m)H(m)
  • AA usa a sua chave privada KAK_{A-} para cifrar H(m)H(m)
  • KA(H(m))K_{A-}(H(m)) serve como assinatura de mm
  • qualquer entidade pode usar a chave pública KA+K_{A+} para validar a assinatura

Infra-estruturas de chaves públicas e certificados

Quando falámos de chaves assimétricas, vimos que corriamos um perigo ao tentar descobrir a chave pública da outra entidade: estávamos suscetíveis ao Men-in-the-middle attack. Esta vulnerabilidade existe já que não conseguimos ter a certeza de que estamos de facto a falar com a entidade pretendida, nem de verificar a autenticidade da chave pública que nos é devolvida.

Há duas formas de evitar este problema:

  • se soubermos de antemão a chave pública de BB, enviamos-lhe a chave simétrica cifrada com a sua chave pública (assim um intruso não consegue obter a nossa chave e fazer-se passar por BB)
  • se existir um certificado digital que confirma que a chave que recebemos é de facto a de BB, BB pode enviar-nos o certificado

As autoridades que emitem estes certificados denominam-se Certification Authorities (CA). Assume-se que a chave pública das CA's é previamente conhecida (normalmente os browsers trazem os certificados associados às CA's pré-instalados).

Um certificado digital consiste num documento que associa uma entidade a uma chave pública e que está assinado pela CA.

Após verificarmos que o certificado recebido está assinado pela CA, ainda precisamos de garantir que a entidade com a qual estamos a contactar é de facto legítima antes de negociarmos uma chave simétrica para usar durante a sessão, e para tal podemos usar a estratégia mencionada previamente que utiliza um nonce:

  • ciframos um nonce com a chave pública retirada do certificado
  • esperamos receber uma versão modificada do mesmo

Por vezes, existe a necessidade de invalidar um certo certificado. Seria caro, se não impossível, rastrear e apagar todas as cópias locais do certificado. A solução mais comum para este problema é incluir uma data de validade no próprio certificado, sendo que a receção de certificados expirados deve ser rejeitada (o titular do certificado deve solicitar a renovação do mesmo).

Troca segura de e-mails

Um exemplo de sistema seguro de troca de e-mails é o PGP, Pretty Good Privacy:

  • cada utilizador possui um par de chaves simétricas
  • divulga a sua chave pública de forma a que outros possam ter acesso e confiança de que lhe pertence
  • para garantir que um e-mail não é alterado:
    • gera uma assinatura criptográfica do conteúdo e assina-a com a sua chave privada
    • o destinatário pode obter o digest original e confrontá-lo com o que é gerado pelo conteúdo que recebeu
  • para garantir que apenas o destinatário lê o e-mail:
    • cria uma chave simétrica para cifrar o conteúdo do e-mail
    • cifra essa chave com a chave pública do destinatário
    • envia o conteúdo cifrado juntamente com a chave simétrica cifrada
    • como o destinatário é o único que possui a sua chave privada, apenas este consegue obter a chave simétrica para decifrar o conteúdo do e-mail

Canais seguros (SSL/TLS)

Seja AA um browser e BB um servidor WWW que pretendem criar um canal seguro. Para tal, podem usar TLS (Transport Layer Security) ou SSL (Secure Sockets Layer, substituído pelo TLS).

Iremos apresentar de uma forma simplificada o funcionamento do protocolo SSL:

  • AA envia um pedido a BB solicitando a sua chave pública, juntamente com um nonce, que será usado para tornar a ligação única
  • BB devolve um certificado com a sua chave pública, juntamente com outro nonce
  • AA verifica a validade do certificado, abortando a ligação caso falhe
  • AA utiliza o nonce recebido para gerar um segredo (designado por "master secret") que irá partilhar com BB
  • AA cifra o segredo com a chave pública de BB e envia-lho
  • BB fica a conhecer também o "master secret"
  • AA e BB criam de forma determinista um conjunto de chaves simétricas que usam para concretizar o canal seguro
    • estas chaves são geradas a partir do "master secret" e dos nonces trocados
    • são criadas 4 chaves:
      • KC=K_C = chave usada para cifrar os dados enviados do cliente para o servidor
      • MC=M_C = chave para assinar, com um MAC, os dados enviados do cliente para o servidor
      • KS=K_S = chave usada para cifrar os dados enviados do servidor para o cliente
      • MS=M_S = chave para assinar, com um MAC, os dados enviados do servidor para o cliente
  • os dados trocados no canal são agrupados em blocos designados por "records"
  • cada record é marcado com um campo que designa o seu tipo
    • existe um tipo de record específico para fechar a ligação
  • cada record é assinado pelo emissor com um MAC
    • para gerar o MAC de um record, o emissor usa a sua chave MM, o tipo do block e um número de sequência
    • MAC =Hash(record||M||type||sequence_number)= \text{Hash(record||M||type||sequence\_number)}
    • impedindo assim que um record seja alterado ou reordenado dentro de uma sequência sem que isso seja detetado
  • os records são ainda cifrados antes de serem enviados, para assegurar a confidencialidade

Autenticação

Já sabemos como podemos estabelecer canais seguros, garantindo a AA que está realmente a comunicar com BB, mas e caso BB queira saber a identidade de AA? Quando um cliente se conecta a uma página web de acesso livre, o servidor não precisa de saber quem AA é, mas isto já não é verdade caso tenha funcionalidades privadas (para saber se pode fornecer o serviço).

Uma solução poderia passar por AA possuir um par de chaves assimétricas, estando a chave pública assinada por uma CA. Mas como AA seria por norma uma pessoa, a solução torna-se pouco prática, já que esta teria de manter o seu certificado com a sua chave pública em todos os seus dispositivos (para além de ter que proteger o certificado para impedir a utilização indevida em caso de roubo).

Geralmente a autenticação é feita através de um segredo que é partilhado entre AA e BB (como uma palavra-passe), e que é utilizado para estabelecer o canal seguro. Este tipo de autenticação pode ser usado em sistemas que usam canais seguros baseados tanto em chaves simétricas como assimétricas.

Autenticação com Chaves Simétricas

  • O cliente e o servidor partilham um segredo (tipicamente a palavra-passe do cliente) a partir do qual é possível derivar uma chave simétrica KAK_A
  • Para estabelecer um canal, o cliente AA envia para o servidor BB o tuplo <A, nonce>\text{<A, nonce>}
  • O servidor gera uma chave simétrica única KK que será usada para estabelecer a comunicação segura e envia-a ao cliente num tuplo cifrado com a chave simétrica partilhada KA(<nonce, K>)K_A(\text{<nonce, K>})
  • Apenas AA pode extrair KK, já que KAK_A vem da sua password
  • Quando AA usar KK, prova a sua identidade

Autenticação com Chaves Assimétricas

  • O cliente AA estabelece um canal seguro com o servidor BB usando um protocolo baseado em chaves assimétricas, semelhante ao SSL/TLS descrito de forma breve anteriormente
  • O cliente usa o canal seguro para enviar as suas credenciais
    • palavra-passe
    • possivelmente outros mecanismos de autenticação adicionais, tais como códigos recebidos por e-mail ou SMS

Autenticação em Múltiplos Serviços

Ambos os protocolos mencionados anteriormente obrigam o cliente a partilhar um segredo (palavra-passe) com cada servidor e a repetir todo o processo de autenticação sempre que quer aceder a um novo serviço. Isto apresenta desvantagens: além de obrigar o cliente a manter várias palavras-passe, torna-se pouco prático e repetitivo quando se quer usar vários serviços dentro de uma mesma organização (Webmail IST, Fénix, Moodle).

Uma solução que não apresenta estes "problemas" é recorrermos a um servidor central de autenticação, no qual tanto os clientes como os servidores confiam:

  • o servidor auxilia o cliente no estabelecimento de um canal seguro entre este e os servidores, sem necessitar de repetir o processo de autenticação
  • o cliente passa a apenas ter que partilhar segredos com o servidor de autenticação
  • os serviços também apenas partilham segredos com este servidor
  • pode ser feito com chaves simétricas ou assimétricas

Protocolo de Needham-Schroeder

O protocolo de autenticação de Needham-Schroeder funciona da seguinte forma:

  1. AS:A,B,NAA \rarr S: A, B, N_A
    • em que NAN_A é um nonce
    • AA pede a SS uma chave para comunicar com BB
  2. SA:{NA,B,KAB,{KAB,A}KB}KAS \rarr A: \Set{N_A, B, K_{AB}, \Set{K_{AB}, A}_{K_B}}_{K_A}
    • SS devolve uma mensagem cifrada com a chave de A KAK_A (obtida através do segredo partilhado: palavra-passe) com os seguintes elementos:
      • a chave gerada para AA comunicar com BB, KABK_{AB}
      • o nonce NAN_A para demonstrar que a mensagem foi enviada em resposta ao pedido de AA
      • um "ticket" cifrado com a chave de BB KBK_B: {KAB,A}KB\Set{K_{AB}, A}_{K_B}, que será entregue por AA a BB na primeira comunicação, servindo de prova a BB que AA está autenticado e se trata de facto de AA
    • como a mensagem vem cifrada com a chave de AA KAK_A, este confia que foi mesmo SS que a enviou, já que apenas este sabe o seu segredo (além de si próprio)
  3. AB:{KAB,A}KBA \rarr B: \Set{K_{AB}, A}_{K_B}
    • AA envia o ticket a BB
  4. BA:{NB}KABB \rarr A: \Set{N_B}_{K_{AB}}
    • BB decifra o ticket e usa a nova chave KABK_{AB} para cifrar um novo nonce, NBN_B
  5. AB:{NB1}KABA \rarr B: \Set{N_B - 1}_{K_{AB}}
    • AA demonstra a BB que foi de facto ele quem enviou o ticket ao devolver uma versão modificada de NBN_B

Passo 3 pode ser replayed

Da forma como o algoritmo está descrito, o passo 3 pode ser replayed por um atacante. Uma versão mais robusta do algoritmo obrigaria AA a enviar um nounce ou um timestamp, {KAB,A,t}KB\Set{K_{AB}, A, t}_{K_B}. Assim, BB pode verificar se tt é recente (esta é a solução adotada no Kerberos).

Sistema de Autenticação Kerberos

Consiste num sistema de autenticação baseado no protocolo de Needham-Schroeder que se tornou um "internet standard". Permite efetuar o que se designa por "single sign-on":

  • o utilizador apenas utiliza as suas credenciais para estabelecer um canal seguro com o servidor de autenticação
  • daí para a frente usa esse canal seguro para obter chaves simétricas para aceder a outros serviços

Sistema Kerberos

Single sign-on com Chaves Assimétricas

Pode-se aplicar o mesmo princípio utilizado no Needham-Schroeder /Kerberos em sistemas com chaves assimétricas. É algo bastante usado hoje em dia por exemplo quando fazemos login num serviço usando a conta Google.

O funcionamento resume-se ao seguinte:

  1. o cliente AA cria um canal seguro com o servidor BB (usando SSL por exemplo)
  2. o servidor BB permite que a verificação da identidade de AA seja feita por um fornecedor de identidades (FI) externo em quem ambos confiam
  3. BB envia a AA um token cifrado com a chave pública de FI FI+\text{FI}_+ que contém informação sobre o cliente de forma a que o FI consiga concluir o processo de autenticação
  4. AA contacta o FI usando a sua palavra-passe (apenas partilhada com FI), entregando-lhe o token
  5. o FI confirma a identidade de AA e que possui uma relação de confiança com o serviço BB
  6. o FI gera um token de acesso cifrado com a chave pública de BB KB+K_{B+} que o cliente AA pode fornecer a BB como prova de que foi autenticado pelo FI
  7. AA entrega o token a BB e conclui assim o processo de autenticação

Nota: os tokens trocados entre BB e FI são cifrados com as respectivas chaves públicas para que o cliente não os consiga alterar.

SSO com chaves assimétricas

Referências

  • Coulouris et al - Distributed Systems: Concepts and Design (5th Edition)
    • Secções 11.1-11.2 e 11.4-11.6
  • Departamento de Engenharia Informática - Slides de Sistemas Distribuídos (2023/2024)
    • SlidesTagus-Aula11
    • SlidesAlameda-Aula12