No último segmento, neste módulo, eu quero te mostrar um ataque geral que afeta muitas implementações de algoritmos Mac. E há uma lição legal ser aprendido a partir de um ataque como este. Então, vamos olhar para uma implementação específica de verificação HMAC. Isto acontece por ser uma implementação da biblioteca Keyczar, que passa a ser escrito em Python. Então aqui está o código que é usado para verificar uma tag gerada pelo HMAC. Este código é realmente simplificada. Eu só queria meio que simplificá-la tanto quanto eu puder para obter o ponto de vista. Então, basicamente, o que o entradas são, a chave, a mensagem, e os bytes de tag. A forma como verificar se ele é, nós re-calcular o HMAC da mensagem e então comparar dizem que a 16, resultando bytes. Para as picadas de assinatura reais dadas. Então, isso parece perfeitamente bem. De fato, qualquer um pode implementá-lo assim. E, de fato, muitas pessoas têm implementado -lo assim. O problema é que, se você olhar como a comparação é feita, o comparação, como se poderia esperar, é feita byte a byte. Há um laço dentro do interpretador Python que faz um loop sobre todos os dezesseis bytes. E acontece que o primeira vez que encontra uma desigualdade, o ciclo termina e diz que as cordas são não igual. Eo facto de que as saídas do comparador quando a primeira desigualdade é encontrado introduz um ataque de temporização significativo sobre esta biblioteca. Então deixe-me mostrar-lhe como se poderia atacá-lo. Então, imagine que você é o invasor, e você tem a mensagem m, para os quais você deseja obter uma marca válida. Agora, seu objetivo é atacar um servidor que tem uma chave HMAC segredo armazenado nele. E o servidor expõe uma interface que basicamente leva pares de mensagem MAC. Verifica se o MAC é válido, se o MAC é válido ele faz algo com a mensagem. E se o MAC não é válido, diz rejeitar. Ok, então ele está de volta ao remetente ou a mensagem rejeita. Então, agora este atacante tem a oportunidade de apresentar, basicamente, muita mensagem que aparece e ver se ele pode deduzir as tags da mensagem específica para a qual uma vez atacada. Aqui está como podemos usar a implementação quebrado a partir do slide anterior para fazer exatamente isso. Então, o que o atacante vai fazer é enviar consultas tag muitas mensagens, onde o mensagem é sempre a mesma. Mas com uma tag, ele vai experimentar com lotes e lotes e lotes de marcas diferentes. Assim, na primeira consulta, o que ele vai fazer é apenas apresentar uma tag aleatório juntamente com a mensagem alvo. E ele vai medir o tempo servidor o levou a responder. A próxima consulta que ele vai apresentar, é que ele vai tentar todos os bytes possíveis primeiros para as marcas. Deixe-me explicar o que quero dizer com isso. Assim, o bytes restantes das tags que ele coloca são apenas arbitrárias, realmente não importa o que eles são. Mas para a primeira mordida, o que ele vai fazer é que ele vai apresentar uma tag de partida com um zero bytes. E então ele vai ver se o servidor teve um pouco pouco mais para verificar a marca do que antes. Se o servidor levou exactamente a mesma quantidade de tempo para verificar a tag como no passo um, então ele vai tentar de novo, desta vez com bytes em um. Se ainda o servidor respondeu muito rapidamente, ele vai tentar com conjuntos de bytes de dois. Se o servidor respondeu rapidamente, em seguida, ele vai tentar com conjuntos de bytes de três, e assim por diante até, finalmente, vamos dizer, quando o byte conjuntos de três servidores do exame um pouco mais para responder. O que isto significa é realmente quando se fez a comparação entre o MAC correto eo MAC apresentado pelo atacante. Os dois combinados sobre este byte, ea rejeição aconteceu na segunda bytes. Aha. Então, agora o atacante sabe que a primeira mordida da tag é definido como três e agora ele pode montar exatamente o mesmo ataque na segunda mordida. Então aqui. É vai apresentar o tag. E o segundo, volta aqui. Aqui Isto deve ir aqui. Assim que vai apresentar uma tag quando o segundo byte é definido para zero. E vai medida se este teve um pouco mais do que na etapa dois. Se não, ele é vai mudar isso para ser definido como um, e ele vai medida se o servidor tempo de resposta é um pouco mais do que antes. Eventualmente, vamos dizer, quando ele define isso, eu não sei. Quando o byte é definido para, a 53, digamos, de repente, o servidor demora um pouco mais para responder. O que significa que agora, o comparador acompanhado nos dois primeiros bytes. E agora o atacante soube que o dois primeiros bytes do Mac são três e 53. E agora ele pode seguir em frente e fazer o mesma coisa no terceiro byte e, em seguida, o byte de quarto e assim por diante e assim por diante. Até que, finalmente, o servidor diz que, sim, eu aceito. Você realmente me deu o Mac direito. E então vamos em frente e agir sobre esta mensagem falsa. Isso, atacar o nosso abastecimento. Então este é um belo exemplo de como um ataque de temporização pode revelar o valor de um MAC, o valor correto do MAC. Tipo de byte por byte, até que finalmente, atacante obtém todos os bytes corretos da marca, e então ele é capaz de enganar o servidor em aceitar este par tag mensagem. A razão de eu gostar deste exemplo é esta é uma maneira perfeitamente razoável de implementação de uma rotina de verificação MAC. E ainda, se você direita-lo desta maneira, ele será completamente quebrado. Então o que fazemos? Assim deixe-me mostrar-lhe duas defesas, a primeira defesa, vou escrevê-lo novamente em python é, é como se segue. Na verdade, a biblioteca Keyczar exatamente implementada essa defesa. Este código é realmente retirado da versão atualizada da biblioteca. O primeiro coisa que fazemos é testar se os bytes de assinatura apresentadas pelo atacante são da comprimento correto, dizem, por HMAC isso seria dizer, você sabe 96 bits ou 128 bits, e se não rejeitamos que, como um MAC inválido. Mas agora, se os bytes de assinatura realmente ter o comprimento correto, o que fazemos é implementar nosso comparador própria. E sempre leva a mesma quantidade de tempo para comparar as duas strings. Assim, em particular, este usa a função zip em Python, que, essencialmente, se você está dando lo duas dezesseis cadeias de bytes. Ele vai criar dezesseis pares. De bytes. Por isso, vou apenas criar um, uma lista de dezasseis elementos, onde cada elemento é um par de bytes. Um tomadas a partir da esquerda e uma tomada a partir da direita. E então você volta, você sabe, você percorrer esta lista de pares. Está calcular o XOR do primeiro par, ea ou para o resultado. Em seguida, é calcular o XOR do segundo par, e você ou que para o resultado. E você nota que, se em algum momento neste loop, dois bytes que ser não igual, então o XOR irá avaliar a algo que é diferente de zero. E, portanto, quando se or'ed-lo para o resultado. O resultado também será contagem em zero, e, em seguida, vamos retornar falso, no final do comparação. Assim, o ponto aqui é que agora o comparador sempre leva o mesmo quantidade de tempo. Mesmo se encontra diferença no número de byte três, será continuar executando as cordas ambos até o fim. E só então se retornar os resultados. Portanto, agora o ataque de temporização supostamente é impossível. No entanto, isso pode ser bastante problemático, porque compiladores tentou ser muito útil aqui. Assim compilador otimizado um pode olhar para este código e dizer: ei, espere um minuto. Eu posso realmente melhorar esse código, tornando o final do circuito fechado quatro. Logo que uma incompatível conjunto de bytes é descoberto. E assim, um compilador otimizado pode ser o seu tipo, de, calcanhar de Aquiles quando se trata de tornar os programas de sempre ter a mesma quantidade de tempo. E assim uma defesa diferente, que não é tão amplamente implementado, é tentar esconder do adversário, o que as cordas são realmente estão sendo comparados. Então deixe-me mostrar você que eu quero dizer com isso. Então, novamente, aqui temos o nosso algoritmo de verificação. Por isso toma como entradas, uma chave, uma mensagem, e MAC de um candidato do adversário. E , em seguida, a forma como fazemos a comparação é que em primeiro lugar, calcular o MAC correto em a mensagem. Mas, então, em vez de comparar diretamente o MAC ea assinatura adversário bytes, o que vamos fazer é nós vamos uma vez mais de hash. Então, nós computar um hash aqui do MAC. Nós computar um hash dos bytes de assinatura. Claro que, se estes dois acontecer a ser a mesma, em seguida, os HMACs resultantes será também o mesmo, assim que a comparação será bem sucedida. Mas a questão é agora, se sig bytes acontecer a MAC igual no primeiro byte, mas não sobre os bytes remanescentes. Então, quando fazemos essa camada adicional de hash, é provável que os dois resultando valores são completamente diferentes. E, como resultado, o byte pelo comparador byte vai saída apenas na primeira iteração. O ponto aqui é que o adversário não realmente sabe quais seqüências estão sendo comparados. E, como resultado, ele não pode montar um ataque de temporização que discutimos anteriormente. Ok, então isso é defesa outro. Pelo menos agora, você não está à mercê de um compilador de otimização. lição O principal de tudo isso é que você percebe que as pessoas que ainda são especialistas em cryptolibraries de execução, obter esse material errado. E o código de direito que as palavras perfeitamente bem e ainda é completamente vulnerável a um ataque de temporização que completamente desfazer toda a segurança do sistema. Então a lição aqui é, naturalmente, você não deve inventar o seu próprio crypto mas você não deve mesmo ser implementar sua própria criptografia, porque muito provavelmente ele estará vulnerável para o lado ataques de canal. Basta usar uma biblioteca padrão como OpenSSL. Keyczar é na verdade um boa biblioteca de usar que reduziria as chances de que você está vulnerável a estes tipos de ataques.