Criptografia Numaboa
O algoritmo Diffie-Hellman
Ter 4 Out 2005 17:36 |
- Detalhes
- Categoria: Chave Pública
- Atualização: Terça, 14 Abril 2009 14:44
- Autor: vovó Vicki
- Acessos: 35178
O algoritmo Diffie-Hellman foi o primeiro algoritmo de chave pública a ser inventado. Isto signidica que seus autores também são os donos da idéia. O algoritmo pode ser usado para a distribuição de chaves, mas não para cifrar ou decifrar mensagens. Sua segurança reside na dificuldade de calcular logaritmos discretos num campo finito comparada com a facilidade de realizar exponenciações no mesmo campo. Se você ficou confuso com tudo isto, não se preocupe. Leia o restante do texto e aprenda a mágica de Diffie-Hellman
Um pouco da história
Whitfield Diffie nasceu em Nova Iorque, EUA, em 1944. Desde criança tinha fascínio pela matemática e foi por isto que acabou estudando no MIT - Massachusetts Institute of Technology, formando-se em 1965. Depois disto trabalhou com segurança de computadores até que, em 1970, estava pronto para uma carreira solo - transformou-se num dos poucos especialistas em segurança realmente independente, sem vínculos com o governo ou com grandes corporações. Seus cabelos longos e seu jeito de ser fazem de Diffie uma espécie de hippie da alta tecnologia e, sem dúvida alguma, pode ser considerado o primeiro cypherpunk da história.
Um dos problemas que mais chamava a atenção de Diffie era o problema da distribuição de chaves. Acompanhando a evolução da organização de pesquisa ARPA (Advanced Research Projects Agency), fundada pelo Departamento de Defesa dos EUA, a qual, em 1969, criou o sistema de comunicação em rede chamado de ARPANet, Diffie sentia que uma revolução estava prestes a acontecer e que o projeto abria as portas para o desenvolvimento de uma supervia de comunicação. O tempo mostrou que seu prognóstico estava certo (em 1982 nascia a Internet) e que sua preocupação com o sigilo e a privacidade dos usuários de uma grande rede era mais do que justificado. Neste contexto, sabia que a criptografia se transformaria numa ferramenta essencial e que o problema da distribuição de chaves se tornaria especialmente agudo.
Em 1974 Diffie foi convidado para dar uma palestra na IBM e o tema, como não poderia deixar de ser, foi sobre as várias estratégias de ataque à distribuição de chaves e propostas para algumas soluções. A reação dos ouvintes não foi das mais calorosas. Os monstros sagrados da IBM, assim como todo mundo, tinham a idéia preconcebida de que este era um problema insolúvel (e não seria um cabeludo que iria mudar as coisas). A única resposta positiva foi a de Alan Konheim, um dos especialistas em criptografia da IBM. Comentou que Martin Hellman, professor da Universidade de Stanford, Califórnia, também havia proferido uma palestra destacando o problema da distribuição de chaves. Foi o que bastou para Diffie atravessar os EUA à procura da pessoa que, aparentemente, era a única que compartilhava suas opiniões.
Martin Hellman nasceu no Bronx, Nova Iorque, EUA, em 1945. Judeu numa vizinhança católica, teve problemas de autoafirmação desde a infância. Ele conta que este foi um dos motivos pelos quais começou a se interessar pela criptografia - já que era diferente, queria ser diferente de vez. Até a inesperada visita de Diffie em 1974, o famoso livro de David Kahn, The Codebreakers, tinha sido o livro de cabeceira e a única fonte de informação de Hellman. Depois de uma meia hora de conversa, um estava impressionado com o conhecimento do outro e perceberam que não estavam mais sozinhos na busca de uma solução "impossível". Apesar das evidentes diferenças de personalidade, este foi o começo de uma grande amizade e companheirismo. Imediatamente começaram a arquitetar um plano para poderem trabalhar juntos. Como Diffie não tinha condições de contratar o novo amigo como pesquisador, Hellman resolveu registrar Diffie como estudante graduado de Stanford. E a peregrinação começou...
Após algum tempo de trabalho conjunto, Ralph Merkle se juntou aos dois. Merkle era um refugiado intelectual de um outro grupo de pesquisa cujo professor não simpatizava nem um pouquinho com as idéias mirabolantes de distribuição de chaves de Merkle. Era o "maluco beleza" ideal e sua ajuda era mais do que bem vinda. Estava formado o trio, os três mosqueteiros desta história.
O problema da distribuição de chaves
O problema da distribuição de chaves é o mesmo que o do ovo e da galinha. Se duas pessoas quiserem trocar mensagens secretas, elas precisam cifrar as mensagens. Para cifrá-las e decifrá-las, precisam de uma chave secreta. Como esta chave também precisa ser transmitida, teria que ser cifrada com outra chave, e assim indefinidamente.
Uma forma bastante simples de resolver o problema das chaves seria usar cadeados. Digamos que Maria queira enviar uma mensagem para João. Ela coloca a mensagem numa caixa de metal, fecha a caixa com um cadeado (só ela tem a chave deste cadeado) e a envia para João. João também coloca um cadeado na caixa (só ele tem a chave deste segundo cadeado) e devolve a caixa para Maria. Ao receber a caixa, Maria abre e retira o seu cadeado e, novamente, envia a caixa para João. Agora, João pode tirar o seu cadeado, abrir a caixa e ler a mensagem. Esquema perfeito? Quase...
Funções matemáticas
Se as funções matemáticas necessárias para cifrar uma mensagem tivessem um comportamento igual ao dos cadeados, a solução encontrada por João e Maria seria perfeita. Infelizmente, este não é o caso As funções matemáticas precisam ser "retiradas" na ordem inversa em que foram "colocadas", o que não é necessário quando se trata de cadeados. Apesar disto, este foi o ponto de partida usado por Diffie e Hellman.
A maioria das funções matemáticas são facilmente reversíveis e, por este motivo, podem ser chamadas de funções bidirecionais (eu costumo chamá-las de funções gangorra ). Uma função multiplicativa é reversível, fácil de resolver e um ótimo exemplo. Digamos que f(x) = 2x. Neste caso, se x = 3, então f(x) = 2 x 3 = 6. Conhecendo a função pode-se calcular x com rapidez, independentemente do tamanho do resultado da função. Por exemplo, se f(x) = 1000, podemos fazer a conta de cabeça e chegar em x = 500. Até aí, nada de muito especial. Acontece que Diffie e Hellman estavam concentrando esforços na procura de uma função unidirecional ou de mão única.
Podemos definir uma função unidirecional como sendo uma função que não tem volta (esta seria a verdadeira função unidirecional) ou cuja volta é tão complicada ou demorada que, na prática, a volta se torna inviável.
A aritmética modular
Uma excelente fonte de funções unidirecionais é a aritmética modular. A aritmética modular é uma área da matemática onde se lida com uma quantidade finita de números arranjados como num mostrador de relógio. Por isto a aritmética modular também é conhecida como aritmética circular. Usando o mostrador do relógio como exemplo, é fácil entender como funciona. A primeira coisa é saber que o mostrador possui apenas 12 números, portanto, o relógio mostra as horas em módulo 12 (este é o campo finito citado na introdução). Apesar desta limitação, costumamos dizer, por exemplo, 15 horas. Como estamos acostumados a raciocinar neste módulo, imediatamente sabemos que o ponteiro das horas está no 3. Na verdade fizemos um pequeno cálculo mental (15 - 12 = 3) que infelizmente não é tão eficiente quando falamos, por exemplo, 43 horas. Onde estará o mostrador do relógio quando são 43 horas? Estará no 7 porque o ponteiro deu 3 voltas completas (3 x 12 = 36) e depois avançou mais 7 posições (43 - 36 = 7). Resumindo, para achar o módulo de um número (ou de uma operação), divide-se este número (ou o resultado) pelo módulo e se considera apenas o resto.
43 (mod 12) = 43 ÷ 12 = 3 com resto 7 --> 43 (mod 12) = 7 59 (mod 5) = 59 ÷ 5 = 11 com resto 4 --> 59 (mod 5) = 4 da mesma forma 2 + 3 (mod 7) = 5 porque 5 ÷ 7 = 0 com resto 5 2 + 9 (mod 7) = 4 porque 11 ÷ 7 = 1 com resto 4 3 x 3 (mod 7) = 2 porque 9 ÷ 7 = 1 com resto 2
O comportamento errático dos resultados modulares faz com que a reversão de uma operação modular seja bem mais trabalhosa do que a reversão de uma operação normal. Se considerarmos a função 4x, por exemplo, à medida que o valor de x aumentar, o valor do resultado também aumenta. A mesma função em qualquer módulo, no entanto, não mostra a mesma linearidade. Observe a seguir:
41 = 4 41 (mod 11) = 4 42 = 16 42 (mod 11) = 5 43 = 64 43 (mod 11) = 9 44 = 256 44 (mod 11) = 3 45 = 1024 45 (mod 11) = 1
Quando os valores são pequenos, como os mostrados no exemplo, montar uma tabela para encontrar o valor de x procurado não é nenhum bicho de sete cabeças. Mas imagine encontrar pela frente alguma coisa como 1793x (mod 32748) ou outros números bem maiores. Em primeiro lugar já haveria um problema com as calculadoras (e, dependendo do tamanho dos números, até com o computador) e, em segundo lugar, o processo pode ser tão demorado que você levaria a vida inteira para achar o resultado correto. É por isto que este é um exemplo clássico de função unidirecional.
Como pesquisadores tarimbados, Diffie e Hellman sabiam que nada podia ser desprezado, mesmo aquilo que parecesse ser coisa que as crianças aprendem no primeiro grau. Depois de dois anos de trabalho com as funções unidirecionais oferecidas pela aritmética modular, Hellman finalmente conseguiu provar o que até então era considerado impossível: remetente e destinatário poderiam usar uma estratégia que punha o problema da distribuição de chaves a nocaute!
O algoritmo Diffie-Hellman
No início de 1976, Hellman estava analisando um axioma que já existe há algumas centenas de anos. A idéia era usar a função na forma de
gx (mod n)
Para que a mágica funcionasse, havia algumas restrições:
g (a base) precisa ser menor do que n (o módulo) e g precisa ser maior do que 1
Para obter as chaves, João e Maria podem trocar informações abertamente, sem a mínima preocupação com alguém que esteja presente ou que eventualmente esteja interceptando estas informações. Em apenas 4 etapas, os dois terão uma chave secreta.
1. A escolha da base e do módulo
Inicialmente João e Maria escolhem dois números grandes, um para a base g e um para o módulo n, obedecendo as restrições citadas acima. Esta escolha não necessariamente envolve apenas os dois, mais pessoas podem participar do grupo de usuários. Para facilitar, será usado um exemplo com números pequenos e apenas com João e Maria. Digamos que eles, durante o intervalo das aulas, tenham concordado com
g = 7 e n = 11
2. A escolha dos expoentes
Depois, na privacidade da sua casa, João escolhe um expoente x bem grande. Este número João mantém cuidadosamente em segredo. Maria faz a mesma coisa e também mantém sua escolha em segredo. De posse dos seus expoentes, os dois calculam o resultado da função:
MARIA JOÃO -------------------------- -------------------------- x = 6 y = 3 M = 76 (mod 11) J = 73 (mod 11) M = 117649 (mod 11) J = 343 (mod 11) M = 4 J = 2
3. A troca de resultados
No dia seguinte, os dois se encontram novamente no intervalo das aulas. Maria entrega o resultado obtido (M=4) para João e este entrega o resultado que obteve (J=2) para Maria. Mais uma vez, nenhum dos dois está preocupado que alguém tome conhecimento destes números.
4. O cálculo da chave secreta
Com o resultado obtido pelo outro, João e Maria voltam a fazer cálculos em particular. Usam a mesma função só que, desta vez, a base usada por Maria é o resultado obtido por João e a base usada por João é o resultado obtido por Maria. Os expoentes continuam sendo os previamente escolhidos:
MARIA JOÃO -------------------------- -------------------------- x = 6 y = 3 J' = 26 (mod 11) M' = 43 (mod 11) J' = 64 (mod 11) M' = 64 (mod 11) J' = 9 M' = 9
Como num passe de mágica, ambos chegaram ao mesmo resultado e agora possuem uma chave secreta em comum
Algumas considerações
A chave secreta nada mais é do que gxy (mod n). Para confirmar, basta fazer os cálculos:
gxy (mod n) = 76 x 3 (mod 11) = 718 (mod 11) = 1.628.413.597.910.449 (mod 11) = 9
Mesmo que se conheça os valores de g, n, M e J não é possível calcular o valor da chave secreta. Se usarmos o método das tentativas (ou seja, a força bruta) poderemos encontrar inúmeros valores que fecham as primeiras equações. Por exemplo, no caso de Maria, os valores possíveis de x são 6, 16, 26, ..., 6 + 10n e, no caso de João, os valores possíveis de y são 3, 13, 23, ..., 3 + 10n. Tanto x quanto y podem ter infinitos valores de acordo com as progressões aritméticas citadas e estes valores precisariam ser agrupados em todos os pares possíveis para tentar encontrar a chave - uma tarefa impossível de ser realizada se os valores escolhidos forem grandes o suficiente.
Mas não são apenas os valores suficientemente grandes dos expoentes que conferem segurança a este sistema. A escolha de g e n também tem uma influência acentuada. O módulo n deve ser um número primo e, mais importante do que isto, (n-1)/2 também deve ser um número primo. A base g, por sua vez, deve ser uma raiz primitiva no módulo n (mais sobre o assunto logo a seguir). Agora, o mais importante de tudo é que n deve ser grande, ter no mínimo 512 bits (ou seja, ter 64 bytes, o que é o mesmo que 64 algarismos). Usar 1028 bits seria mais seguro.
Operações modulares da Teoria dos Números
Normalmente as operações modulares e os números primos são conceitos fáceis de serem absorvidos. Estes conceitos fazem parte da Teoria dos Números, uma área da matemática que lida apenas com números inteiros. Uma das coisas que sempre me chamou a atenção é que os matemáticos adoram encontrar particularidades e certas características de comportamento dos números. Como não sou matemática, vejo isto como uma mania de querer descobrir a personalidade dos números, o que transforma a matemática numa investigação de detetive, num jogo de caça ao tesouro ou numa brincadeira de "o que é, o que é?". Isto me ajuda um bocado
Raiz Primitiva
Por exemplo, fui dar uma olhada no que é a raiz primitiva de um módulo. Descobri que um número g é a raiz primitiva de um módulo n quando este número elevado às potências de 1 até n-1 (mod n) fornecer todos os resíduos possíveis deste módulo. Por exemplo, 3 é uma raiz primitiva do (mod 5) porque:
31 (mod 5) = 3 (mod 5) = 3 32 (mod 5) = 9 (mod 5) = 4 33 (mod 5) = 27 (mod 5) = 2 34 (mod 5) = 81 (mod 5) = 1
Estas operações resultaram em todos os resíduos que o módulo 5 pode oferecer. O fato de não estarem em ordem não tem importância, pois a premissa é que todos apareçam uma vez. Apenas para fixar esta noção, observe o comportamento de 4 no módulo 5:
41 (mod 5) = 4 (mod 5) = 4 42 (mod 5) = 16 (mod 5) = 1 43 (mod 5) = 64 (mod 5) = 4 44 (mod 5) = 256 (mod 5) = 1
Estes cálculos nos mostram que 4 não é uma raiz primitiva do módulo 5. Quando o valor dos módulos é pequeno, pode-se fazer o cálculo com lápis e papel, mas, se o valor do módulo for muito grande, a calculadora não vai ter espaço para os dígitos e os cálculos vão levar um tempo enorme. Ainda bem que os matemáticos acham atalhos que facilitam a nossa vida. Conforme Burton publicou em 1986, um dos atalhos que podemos pegar é
Se o MDC(g,n)=1 (ou seja, g e n são primos entre si) e a ordem multiplicativa de g (mod n) for igual a φ(n), onde φ(n) é a função totiente, então g é uma raiz primitiva do módulo n.
Deu nó na sua cabeça? Pra falar a verdade, na minha também deu. É que estão faltando algumas peças para resolver este quebra-cabeça. O MDC, ou máximo divisor comum, não tem segredos. Já a ordem multiplicativa e a função totiente...
Ordem Multiplicativa
O jeito é ir por partes. A ordem multiplicativa, também chamada de ordem modular, Haupt-exponent (expoente principal) ou simplesmente ordem, é uma característica dos módulos (mais um dos seus traços de pesonalidade ) Se obtivermos a resposta para a pergunta "Qual é o expoente de um número (mod n) para que o resultado seja 1?", saberemos a ordem deste número neste módulo. Por exemplo, a ordem de 2 (mod 7) é igual a 3 porque 21 (mod 7) = 2, 22 (mod 7) = 4 e 23 (mod 7) = 1. Como o resultado procurado é o expoente 3, a ordem multiplicativa de 2 (mod 7) = 3. Reveja os cálculos que foram feitos para achar uma das raízes primitivas do módulo 5. Eles também nos mostram que a ordem de 3 (mod 5) = 4.
Mas, e se o módulo for muito grande? Será que precisamos calcular um monte de potências módulo até descobrir qual é a ordem multiplicativa de um número neste módulo? Alguns matemáticos famosos já cuidaram disso, facilitando as coisas para nós.
O Pequeno Teorema de Fermat
Fermat nos conta que, se o módulo n for um número primo e se o número g não for um múltiplo de n, então a ordem multiplicativa do número g no módulo n é igual a n-1 porque
gn-1 (mod n) = 1
Função Totiente de Euler
A função totiente de Euler, também conhecida como função phi de Euler, é designada por phi(n) ou φ(n). Esta função, onde o n representa um módulo, nos revela mais uma faceta modular: indica quantos resíduos (os restos das divisões) deste módulo são primos em relação a n. Por exemplo, no módulo 6, os resíduos possíveis vão de 1 a 5. Como o valor zero indica ausência de resíduo, ele não é considerado. Agora, comparando 6 com cada elemento do conjunto de resíduos possíveis, quando é que estes números são primos entre si? Acompanhe:
6 e 1 --> Sim, o único divisor comum é 1, ou seja, MDC(6, 1) = 1 6 e 2 --> Não, ambos são divisíveis por 1 e 2 6 e 3 --> Não, ambos são divisíveis por 1 e 3 6 e 4 --> Não, ambos são divisíveis por 1 e 2 6 e 5 --> Sim, MDC(6, 5) = 1
De acordo com os resultados, φ(6) é representado pelo conjunto de dois elementos {1, 5}, ou seja, φ(6) = 2. Aí acontece mais uma coisa interessante: quando n for um número primo, todos os resíduos são relativamente primos a n. Se soubermos disso de antemão, não será preciso calcular nenhum MDC, é só lembrar que o zero é a ausência de resíduo. Então, φ(7) = 6, φ(5) = 4 e, generalizando, φ(n) = n - 1 E tem mais uma dica. Se o módulo for um número composto por dois fatores primos p e q, então
phi(n) ou φ(n) = (p - 1) x (q - 1)
Para conferir, basta fazer as contas com o módulo 6. Como 6 é composto pelos números primos 2 e 3, então phi(6) = (2 - 1) x (3 - 1) = 1 x 2 = 2. Guarde bem esta última fórmula porque ela aparece uma porção de vezes em algoritmos de chave pública!
Mas Euler também nos forneceu uma outra ferramenta muito útil que serve para calcular a ordem multiplicativa de um número num módulo que não seja primo. Acabamos de ver que Fermat quebrou o galho para os módulos que são primos. Euler generalizou o Pequeno Teorema de Fermat e quebrou um galho ainda maior.
A generalização de Euler do Pequeno Teorema de Fermat
Euler nos ensina que, se o MDC(g, n) = 1, ou seja, se o número g e o módulo n forem primos entre si, então a ordem multiplicativa de g (mod n) é igual a phi(n) porque
gφ(n) (mod n) = 1
Conferindo a raiz primitiva calculada no início
No exemplo 3 (mod 5), de acordo com aquela afirmação de Burton que deu nó na minha cabeça, se a ordem multiplicativa 3 (mod 5) e a função totiente phi(5) forem iguais, então 3 é uma raiz primitiva do módulo 5. Por outro lado, se os resultados forem diferentes, 3 não é uma raiz primitiva do módulo 5. Como já fizemos os cálculos e determinamos que 3 é uma raiz primitiva do módulo 5, então a ordem multiplicativa de 3 (mod 5) e phi(5) precisam ser iguais. Burton parece ter razão, elas são mesmo iguais: ordem multiplicativa de 3 (mod 5) = 4 e phi(5) = 4.
Raiz primitiva de um módulo grande
As ferramentas citadas neste texto ajudam a provar com rapidez se determinado número é ou não uma raiz primitiva de determinado módulo, mesmo quando este módulo tiver um valor muito grande. Veja mais um exemplo: 143 é uma raiz primitiva do módulo 1142? Para responder esta pergunta, a primeira providência é verificar se 143 e 1142 são primos entre si:
143 | 11 13 | 13 --> Os divisores de 143 são 11, 13 e 1 1 | 1142 | 2 571 | 571 --> Os divisores de 1142 são 2, 571 e 1 1 | O único e o máximo divisor que estes números têm em comum é 1, ou seja MDC(143, 1142) = 1 mostra que 143 e 1142 são primos entre si.
A seguir, calculamos o phi(1142). Como 1142 é um número composto pelos fatores 571 e 2, o phi(1142) pode ser calculado de acordo com a fórmula
phi(n) = (p - 1) x (q - 1) phi(1142) = (571 - 1) x (2 - 1) = 570
Agora é só confirmar se a ordem multiplicativa de 143 (mod 1142) também é igual a 570, ou seja, se 143570 (mod 1142) = 1. Como o módulo 1142 não é um número primo, não vamos poder usar o Pequeno Teorema de Fermat, mas, em compensação, como o MDC(143, 1142) = 1, eles são primos entre si e podemos apelar para a generalização que Euler fez deste teorema, o qual nos diz que:
gφ(n) (mod n) = 1 ou seja, de acordo com Euler, 143φ(1142) (mod 1142) = 1 143570 (mod 1142) = 1 e, se ainda houver dúvidas, é só calcular para verificar que 3,4796964099440242706248097324932e+1228 (mod 1142) = 1
Conferindo os valores de João e Maria
Será que nossos amigos cuidaram para que os valores usados com o algoritmo Diffie-Hellman realmente oferecessem o máximo de segurança possível? Descontando o fato de que propositalmente foram escolhidos valores pequenos para a base e para o módulo afim de facilitar o acompanhamento do exemplo, ainda falta avaliar alguns itens da checklist:
- O módulo n deve ser um número primo: o módulo escolhido foi 11, que é primo --> OK
- (n-1)/2 também precisa ser primo: (11 - 1) / 2 = 10 / 2 = 5, que é primo --> OK
- A base g precisa ser uma raiz primitiva no módulo n: OK (veja abaixo)
Os escolhidos foram g = 7 e n = 11. MDC(7, 11) = 1 (são primos entre si) phi(11) = (11 - 1) = 10 (phi de número primo) Como n é primo e g não é um múltiplo de n, o Pequeno Teorema de Fermat é aplicável: 710 (mod 11) = 282.475.249 (mod 11) = 1 (a ordem multiplicativa de 7 (mod 11) é 10) phi(11) = 10 | | --> 7 é uma raiz primitiva no módulo 11 ordem 7 (mod 11) = 10 |
Diffie-Hellman estendido
V. S. Miller e Kevin McCurley estenderam este algoritmo para curvas elípticas e Taher ElGamal usou a idéia básica para desenvolver um algoritmo de encriptação e de assinatura digital. Além disso, o protocolo de troca de chaves pode ser facilmente estendido para atender três ou mais pessoas. Se João, Maria e Onofre quiserem gerar uma chave secreta, o procedimento é o seguinte:
1. Maria escolhe um inteiro grande qualquer x e calcula X = gx (mod n) 2. João escolhe um inteiro grande qualquer y e calcula Y = gy (mod n) 3. Onofre escolhe um inteiro grande qualquer z e calcula Z = gz (mod n) 4. Maria envia X para João, João envia Y para Onofre e Onofre envia Z para Maria. 5. Maria calcula Z' = Zx (mod n) 6. João calcula X' = Xy (mod n) 7. Onofre calcula Y' = Yz (mod n) 8. Maria envia Z' para João, João envia X' para Onofre e Onofre envia Y' para Maria. 9. Maria calcula k = Y'x (mod n) 10. João calcula k = Z'y (mod n) 11. Onofre calcula k = X'z (mod n)
A chave secreta k é igual a gxyz (mod n) e este protocolo pode ser facilmente estendido para quatro ou mais pessoas.
Sugestões
Se você precisar de mais algumas ferramentas on line, procure-as na Escolinha da Aldeia na Caixa de Ferramentas. Sugestões: MDC - Máximo Divisor Comum, Este número é primo?, Aritmética Modular, Logaritmos e Potenciação. Divirtam-se com o Diffie-Hellman e um grande abraço da
vovó Vicki
Fontes
- Bruce Schneier, "Applied Cryptography"
- Simon Singh, "O Livro dos Códigos"
- Number Theory - Congruences
- David Morgan, Primitive roots and Diffie-Hellman key exchange>/li>