Criptografia assimétrica e usando GnuPG

Criptografia é a “arte” de esconder algo mediante o uso de uma chave, conhecida pelos intelocutores da mensagem apenas. A “mensagem” será ininteligível para qualquer outro participante da conversa. O promeiro exemplo de criptografia “formal” que se tem notícia (pelo menos a que posso pensar agora) é o método usado por Julio Cesar: A idéia é atribuir valores aos caracteres da mensagem e deslocar esses valores em algum outro valor fixo. Atualmente, existe o método chamado ROT13, onde a cada caracter é somado o número 13. Neste caso, a mensagem “MENSAGEM SECRETA” ficará assim: “ZRAFNTRZ FRPERGN”.

Com ROT13 os interlocutores têm apenas que saber o quanto devem deslocar o valor de cada um dos caracteres e essa é a chave para a decodificação. No entanto, perceber o artifício é algo muito fácil… Outro método é usar a operação lógica XOR para “codificar” a mensagem através de uma string “chave”. Por exemplo, se quiséssemos codificar a mensagem “MENSAGEM SECRETA” com a chave “SEGREDO”, poderíamos fazer algo assim:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char msg[] = "MENSAGEM SECRETA";
char key[] = "SEGREDO";

static size_t encode(char *, char *);

void main(void)
{
  size_t i, size;

  printf("Megsagem: \"%s\"\n"
         "Chave: \"%s\"\n",
         msg, key);

  size = encode(msg, key);

  for (i = 0; i < size; i++)
    printf("%02X ", msg[i]);
  puts("");
}

size_t encode(char *msg, char *key)
{
  size_t size = 0;
  char *p = key;

  while (*msg)
  {
    *msg++ ^= *p++;
    if (!*p) p = key;
    size++;
  }

  return size;
}

O resultado:

Megsagem: "MENSAGEM SECRETA"
Chave: "SEGREDO"
1E 00 09 01 04 03 0A 1E 65 14 17 06 16 0A 07 04

O problema, em C, é que a string resultante teria apenas 1 byte de tamanho (o “E” de “MENSAGEM” é zerado pelo XOR com o “E” de “SEGREDO”). Mas, é mais difícil decodificar esse stream de bytes e obter a “MENSAGEM SECRETA” sem o conhecimento da chave “SEGREDO” por ambos os interlocutores.

Esse tipo de criptografia, onde as duas partes têm que conhecer o segredo, é chamada de “simétrica” e apresenta o problema de que a chave, usada para desvendar a mensagem, deve ser transmitida em segredo para os participantes. Qualquer um com o segredo em mãos pode decodificar a mensagem… Imagine o cenário em que vocẽ transmite para um amigo, via e-mail, a chave e EU, sendo o sacana que sou, consigo interceptar sua mensagem contendo a chave! Ou seja, eu sou o “homem no meio” (man in the middle). Daqui para frente, todas sa mensagens criptografadas com essa chave que você passar para seu amigo eu também conseguirei ler!

O problema é que vocẽ precisa de um meio seguro de enviar a chave para o destinatário e, aparentemente, não há maneira de fazer isso: Você pode fazer uma ligação telefônica para seu amigo e eu posso ter “grampeado” seu telefone… Você pode escrever um bilhete para seu amigo e enviá-lo pelo correio, mas eu posso ter acesso à sua correspondência de algum modo… e por ai vai… E não adianta pensar em telepatia, porque você não conhece meus poderes! :)

Mas, não tema… em meados dos anos 70 um par de sujeitos barbudos (Whitfield Diffie e Martin Hellman) publicaram um trabalho contendo o conceito de criptografia “assimétrica”. A coisa funciona mais ou menos assim: Os interlocutores têm duas chaves, ao invés de uma só. Uma chave “pública” que é distribuída para quer quer que seja, e uma “privada” que pertence apenas à pessoa e ninguém mais… A criptografia da mensagem é então feita de forma tal que apenas minha chave “privada” consegue decodificar o que foi codificado por minha chave “pública” e vice versa… Como eu tenho a chave pública do meu interlocutor e ele tem a minha, eu trancafio a mensagem usando minha chave privada e, depois, trancafio essa nova mensagem com a chave pública dele. Somente meu interlocutor será capaz de abrir a mensagem com sua própria chave “privada” e, depois, usar minha chave pública para decodificá-la em sua forma final.

Isso tem alguns pontos interessantes:

  1. O “homem do meio” jamais conseguirá decodificar a mensagem, pois precisa da chave privada do destinatário;
  2. O “homem do meio” jamais poderá se passar pelo enviador da mensagem, pois não tem sua chave privada;
  3. Apenas parte das “chaves” são passadas à diante (metade delas é “privada”);
  4. Não é necessário um “meio seguro” para o trânsito das chaves “públicas” e da mensagem criptografada!

O algorítmo RSA:

Para alcançar esse intento, três outros sujeitos, criaram um algoritmo baseado num teorema chamado de “o pequeno teorema de Fermat”. Ele diz, quando a e p são primos entre si:

\displaystyle a^{p-1} \equiv\,1\,(\mod p)

Essa notação significa algo assim: a^{p-1} - 1 é múltiplo de p… A matemática por trás desse teorema pode ser estudada neste link. E o seu uso no RSA, aqui. Em resumo, chega-se ao fato de que:

\displaystyle {m^e}^d \equiv\,m\,(\mod n)

Onde e, d e n são partes da chave privada (no par (e,n)) e pública (no par (d,n)). Ainda, a equação acima também é verdadeira para {m^d}^e \equiv\,m\,(\mod n), já que {a^b}^c = a^{b\cdot c}. E essas relações tem ainda uma característica prática interessante para a criptografia: Mesmo que o “homem do meio” saiba os valores de d e n (a chave pública), encontrar os valores de m e e originais é muito difícil! Especialmente porque n é um valor muito grande (atualmente os certificados usam 2048 ou 4096 bits) e o expoente pode ter uns 512 bits de tamanho. Observe os dados do certificado contido no wordpress, para este blog:

$ openssl s_client -connect bitismyth.wordpress.com:443 -showcerts | \
  openssl x509 -noout -text
...
Subject Public Key Info:
  Public Key Algorithm: rsaEncryption
    Public-Key: (2048 bit)
      Modulus:
        00:c3:8b:a8:b1:25:40:89:b0:40:52:8c:ab:75:28:
        ff:76:24:f5:2b:95:7a:e5:58:90:35:53:66:90:79:
        f0:f8:99:09:ee:aa:d9:ff:24:68:84:e6:85:0a:05:
        7c:53:2f:e3:8e:16:ab:42:bd:93:bd:9a:1c:ad:58:
        86:a1:29:53:b7:0d:bc:46:71:7d:3a:d6:fa:e6:ee:
        52:be:77:89:99:1f:61:2e:e3:39:11:d8:76:41:ae:
        28:16:69:ca:c2:c9:f3:f9:3e:0e:6e:13:b8:e4:30:
        18:dc:c4:29:a9:6e:02:e5:9d:59:dd:97:98:81:21:
        78:3d:a4:ce:56:1e:cb:b2:73:be:a5:e1:a7:ac:26:
        8c:25:61:28:3f:7a:e8:02:81:35:ca:0b:f1:63:ad:
        31:d5:4f:21:19:91:d4:8d:85:20:dd:5d:15:31:b8:
        bc:a7:b8:60:f9:bb:4a:24:4d:43:e9:1e:32:e0:5f:
        1d:bf:25:fd:9d:c7:1d:d1:8e:ae:86:67:7d:1e:9d:
        25:67:66:b7:c6:7c:26:89:c0:80:0d:81:50:e1:82:
        07:db:01:e8:18:49:bc:c6:81:5d:07:f6:ac:18:9c:
        44:ef:8d:13:a4:0e:78:46:1e:b3:04:8e:12:a3:dc:
        55:1f:55:4b:18:60:ab:41:c8:1c:d5:e8:82:0e:8e:
        da:f9
      Exponent: 65537 (0x10001)
...

Assim, para criptografar uma mensagem, a equação c \equiv\,m^e\,(\mod n) é usada, mas para decodificá-la, usamos a equação c^d \equiv\,{m^e}^d \equiv\,m\,(\mod n), onde os expoentes e e d são cuidadosamente escolhidos, bem como o módulo n… Em primeiro lugar, os expoentes são calculados com base em dois valores primos. Depois, n é calculado como a multiplicação desses dois valores primos iniciais. Além da aritmética modular exponencial nos dar a vantagem da dificuldade de encontrar expoentes corretos, o fato desses cálculos envolverem valores primos dificulta mais um bocado, já que fatorar valores primos a partir de um módulo enorme não é tarefa computacionalmente fácil. Especialmente porque, no caso da chave privada, o expoente também é grande!

A coisa é ainda um pouco mais complicada que isso!

Pode parecer simples, afinal temos apenas 3 “constantes” para nos preocuparmos, certo? Acontece que RSA conta com 8 fatores (não apenas 3). A escolha das chaves, por exemplo, depende da escolha de dois valores primos, entre si, de forma aleatória confiável e atendendo a condições específicas que não vale a pena esmiuçar aqui. Afinal, não queremos nem os expoentes e nem o módulo com valores pequenos previsíveis.

Outra coisa a se levar em conta é que as equações são de execução lenta, em comparação à criptografia simétrica. Não que isso faça muita diferença hoje em dia, mas os padrões de transporte de dados criptografados, por exemplo SSL e TLS, usam a criptografia assimétrica apenas para criptografar uma chave simétrica gerada “on the fly”. Isso quer dizer que os dados mesmos são transmitidos por criptografia simétrica (agradeço aos amigos Henrique Manoel e Vitalino Victor por terem me chamado a atenção para esse ponto!).

Certificados Digitais?

Um certificado é uma estrutura de dados que contém sua identidade (quem é o dono da coisa?), sua chave pública, a assinatura de alguém mais confiável do que você (no caso de certificados x509, da “autoridade certificadora”), dando autentificade à chave pública, e outros pequenos detalhes como, por exemplo, as datas onde estas informações possam ser consideradas válidas e um “número de série”. Clique no cadeado, lá em cima, antes da editbox contendo a URL deste site e veja essas informações sobre o certificado deste site. No caso deste certificado específico, ele foi gerado pelo “wordpress.com” (Subject) e assinado pelo “Go Daddy” (Issuer – que é a autoridade certificadora).

Mas, pera ai… E quanto a autenticicade do “Go Daddy”? Bem… Seu browser já vem com o certificado contendo a chave pública do “Go Daddy” para a validação… Ou seja, um certificado é validado contra a chave pública contida em outro certificado de nível superior, comumente nomeados de root certificates ou “certificados raiz”.

Certificado deste blog
Certificado deste blog

Se preferir, use o comando openssl que usei anteriormente e obtenha todas as informações do certificado…

Mas, atenção: Um certificado não contém quaisquer informações sobre a chave privada. Sua chave privada é sua e de mais ninguém… Assim, como a chave privada do wordpress é dele e ninguém deve ter acesso a ela.

Usando GPG

O mesmo ocorre quando usamos algum utilitário de criptografia assimétrica como o GnuPG ou PGP. Tudo o que você distribui para os outros é o certificado contendo a chave pública… Sua chave privada deve ficar protegida e ninguém, a não ser você, tem acesso a ela… De fato, no Linux, é comum que o keystore contendo as chaves privadas não tenham permissões para outros usuários que não o owner:

$ ls -go ~/.gnupg/secring.gpg
-rw------- 1 7513 Out 6 20:27 secring.gpg

Além disso, no caso do keystore contendo as chaves públicas (~/.gnupg/pubring.gpg), os certificados são assinados (quando o são!) por outros usuários que você considere confiáveis… Assim como você também pode assinar os certificados de outros usuários que você considere confiáveis!… O princípio é o mesmo dos certificados x509, mas sem a figura de uma “autoridade certificadora”… Para determinar a confiabilidade desses certificados você deve conferir as informações por algum canal que considere “seguro”… Mas, note… Você não está trocando as chaves, só conferindo dados com base em alguma matemática arcana. É o caso do fingerprint, por exemplo.

Deixe-me estressar isso, antes de mais nada: O GnuPG e o PGP foram criados para criptografar e decriptografar informações usando o esquema de assimétrico mas, em essência, ele não está nem ai para a confiabilidade das chaves. É tarefa do usuário garantir que tenha chaves confiáveis e existem meios para que isso seja garantido, usando alguma inteligência…

Suponha que você coloque as mãos em um certificado contendo minha chave pública (pode obtê-la facilmente usando o GnuPG, como mostrado abaixo):

$ gpg --recv-keys fredericopissarra@gmail.com

Como o GnuPG não liga para a autenticidade da chave, se você me conhece, basta fazer uma ligação telefônica pra mim e me perguntar se o fingerprint de meu certificado é o que você obtém na linha de comando abaixo:

$ gpg --fingerprint --list-keys fredericopissarra@gmail.com
pub   4096R/C09C2054 2016-10-06 [expires: 2019-10-06]
      Key fingerprint = 11A5 2C9C E02A 24AA EBFC  046B 20AA 0246 C09C 2054
uid                  Frederico Lamberti Pissarra <fredericopissarra@gmail.com>
sub   4096R/F9AA8B75 2016-10-06 [expires: 2019-10-06]

Se você está satisfeito com minha resposta, basta assinar minha chave e mandar de volta para a internet (por favor, não faça isso sem uma confirmação do fingerprint… você só estará colocando a si mesmo em risco se essa chave não for a minha!):

$ gpg --sign-key fredericopissarra@gmail.com
$ gpg --send-keys fredericopissarra@gmail.com

O ponto aqui é que você tem que encontrar algum canal de comunicação comigo que seja seguro. Pode ser até por linguagem de sinais ou mensagens de fumaça, não importa… Desde que você e eu tenhamos certeza que seja seguro o suficiente para que ninguém possa se passar por mim…

É claro que, antes que você possa fazer isso, terá que ter gerado seu próprio par de chaves (usando a linha de comando “$ gpg --gen-key“)… E antes que a sua assinatura chegue a constar no meu keystore tenho que ter confiado na sua chave e, para isso, preciso de sua chave pública e precisarei ligar pra você para conferir o fingerprint

Para exportar seu certificado existem duas opções: Usar a linha de comando abaixo e obter um arquivo texto chamado pubkey.asc, contendo o certificado… Ou enviá-lo para um diretórios de chaves e me enviar a sua identificação (e-mail, por exemplo):

$ gpg -o pubkey.asc -a --export <seu-email-aqui>

Sobre a confirmação de confiabilidade, note que o fingerprint não é a única informação… Sua chave tem um hash. O hash “simplificado” da chave pública acima é C09C2054. Você pode obter o hash “completo” com:

$ gpg --keyid-format long --fingerprint \
  --list-keys fredericopissarra@gmail.com
pub   4096R/20AA0246C09C2054 2016-10-06 [expires: 2019-10-06]
      Key fingerprint = 11A5 2C9C E02A 24AA EBFC  046B 20AA 0246 C09C 2054
uid                          Frederico Lamberti Pissarra <fredericopissarra@gmail.com>
sub   4096R/DFF95257F9AA8B75 2016-10-06 [expires: 2019-10-06]

O hash “longo” é 20AA0246C09C2054. Há também as datas de validade, e meu nome e endereços completos, bem como o tamanho da chave e o algoritmo (4096 bits, RSA)…
Esse “hash” é, na verdade, o verdadeiro identificador “único” do certificado e pode ser usado no lugar do meu e-mail, nas linhas de comando.

Usando GPG para enviar e-mails criptografados e/ou assinados

O plugin mais famoso para usar GPG em clientes de e-mail como Thunderbird é o Enigmail. No caso do Outlook, o GnuPG para Windows (aqui) distribuí um módulo para ele e o instala automaticamente.

Usando GPG para assinar commits e tags no Github

O GIT permite que você assine commits e tags e o Github valida esses objetos desde que sua chave pública esteja cadastrada lá. No caso de commits, basta adicionar a opção -S na linha de comando. No caso de tags, a opção -s. Se você possuir apenas um par de chaves nos seus keystores, elas serão as default, caso contrário, você pode editar o arquivo ~/.gnupg/gpg.conf e alterar a linha contendo default-key, alterando o id da chave para a sua preferida.

Outros sistemas de controle de versão parecem ter suporte para o GPG também. Acredito, mas não estou certo, que o subversion e o Maven o tenham…

Usando GnuPG para criptografar simétricamente:

Vocẽ também pode fazer uma criptografia simétrica usando, por exemplo, AES. Para saber quais os algoritmos estão disponíveis na sua instalação do GnuPG basta pedir a versão:

$ gpg --version
gpg (GnuPG) 1.4.20
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Pode default o GnuPG usa AES128 (ou, simplesmente AES). Para criptografar simetricamente com o GnuPG você pode fazer:

$ gpg -o <arquivo criptografado> -c \ 
  -e <arquivo original>

A seguir uma chave será pedida duas vezes… Se quiser mudar o algoritmo use a opção --cipher-algo e informe uma das opções de cifras acima. O GnuPG automaticamente usa ZLIB para comprimir os dados criptografados, é claro que você também pode mudar isso usando a opção --compress-algo (eu não recomendo. ZLIB é padrão e muitas vezes dá resultado melhor que o ZIP).

Anúncios