Análise do ataque quadrado ao AES
|
|
|
- Leandro Caires de Sá
- 7 Há anos
- Visualizações:
Transcrição
1 UNIVERSIDADE FEDERAL DE SANTA CATARINA CURSO DE GRADUAÇÃO EM CIÊNCIAS DA COMPUTAÇÃO Paulo Soto de Miranda Análise do ataque quadrado ao AES Trabalho de Conclusão de Curso Daniel Santana Freitas Florianópolis, Agosto de 2005
2 Depois que conhece uma nova idéia, a mente do homem nunca pode voltar a suas dimensões originais. Oliver Wendell Holmes Jr. ii
3 iii Ofereço esse trabalho à minha família e namorada.
4 Agradecimentos Agradeço principalmente os meus pais que tornaram possível a minha entrada na faculdade e que sempre me apoiaram quando precisava. Ao professor Daniel Santana por me orientar nesse trabalho e tirar minhas dúvidas com muita atenção. Aos membros do Labsec que me ajudaram em questões técnicas e que sempre foram ótimos companheiros de trabalho. Também agradeço à minha namorada e amigos por terem aguentado meus momentos de nervosismo e preocupação.
5 Resumo Este trabalho é uma análise teórica e computacional de diferentes ataques quadrados aplicados ao algoritmo criptográfico AES. A análise teórica aborda os fundamentos matemáticos usados no AES e nos ataques, a descrição detalhada do projeto do AES e a descrição de três tipos de ataques quadrados: o ataque de primeira ordem sobre 4 e 6 rodadas e o ataque de quarta ordem sobre 5 rodadas do AES. A análise computacional consiste na implementação do AES e dos três tipos de ataques na linguagem de programação C++. Esses ataques foram elaborados por criptoanalistas e apresentados em congressos científicos, mas suas demostrações se restringiram apenas à teoria. O mérito desse trabalho é demostrar computacionalmente o funcionamento desses ataques. Palavras-Chave: Criptoanálise, AES, Ataque Quadrado.
6 Sumário Resumo 1 Sumário 2 Lista de Figuras 4 Lista de Tabelas 5 Lista de Siglas 6 1 Introdução 7 2 Fundamentos Matemáticos Aritmética Modular Aritmética em Corpos de Galois Aritmética Polinomial O AES ByteSub ShiftRow MixColumn AddRoundKey Derivação de chave O Ataque Quadrado Ataque de primeira ordem sobre 4 rodadas a Rodada a Rodada
7 a Rodada a Rodada Ataque de primeira ordem sobre 6 rodadas Extensão no final Extensão no início Ataque de quarta ordem sobre 5 rodadas Considerações Finais e Trabalhos Futuros 40 Referências Bibliográficas 41 Apêndice 42 A Código Fonte 42 B Artigo 88 Abstract 1 B.1 Introdução B.2 O Ataque Quadrado B.2.1 Ataque de primeira ordem sobre 4 rodadas B.2.2 Ataque de primeira ordem sobre 6 rodadas B.2.3 Ataque de quarta ordem sobre 5 rodadas B.2.4 Conclusão
8 Lista de Figuras 3.1 Estrutura do AES ByteSub [1] ShifRow [1] MixColumn [1] AddRoundKey [1] Derivação de chave Ataque 4 rodadas Estensão no final Extensão no início B.1 Ataque 4 rodadas B.2 Estensão no final B.3 Extens? no in?io
9 Lista de Tabelas 2.1 Propriedades da Aritmética Modular
10 Lista de Siglas AES - Advanced Encryption Standard DES - Data Encryption Standard C/C++ - Linguagem de Programação NIST - National Institute of Standards RAM - Random Access Memory GF - Galois Field ByteSub - substituição byte a byte através de consultas a uma tabela InvByteSub - trasformação inversa a ByteSub ShiftRow - permutação simples através de deslocamento de linhas InvShiftRow - trasformação inversa a ShiftRow MixColumn - substituição através de operações sobre uma coluna InvMixColumn - trasformação inversa a MixColumn AddRoundKey - aplicação de ou-exclusivo entre o bloco e a chave. BS - ByteSub SR - ShiftRow MC - MixColumn KA - AddRoundKey S-Box - tabela de substituição usada na ByteSub CPU - Central Processing Unit
11 Capítulo 1 Introdução A tecnologia da informação tem evoluído muito e englobado várias áreas da sociedade. Algumas dessas áreas lidam com informações muito importantes e sigilosas, como transações bancárias e estratégias governamentais. Logo, o domínio da segurança de dados se tornou essencial. A segurança de dados é composta por diversos serviços que provém às informações do usuário: Confidencialidade: proteção contra leitura não autorizada; Não-repúdio: prevenção de repúdio por parte da origem da informação. Por exemplo, previni um emissor de uma mensagem negar a sua autoria; Autenticação: garantia que a comunicação é autentica. Provar que os comunicantes são realmente quem eles dizem ser; Integridade: garantia que a informação não foi alterada. A base para esses serviços de segurança é a criptografia. Ela é um processo usado para transformar um conjunto de dados legíveis quaisquer em um conjunto de dados ininteligível. Essa operação é chamada de cifragem e a sua inversa de decifragem. Existem dois tipos de criptografia: simétrica e assimétrica. Na simétrica, um segredo, a chave, é usado para fazer a cifragem e o mesmo segredo é usado para a decifragem. Na assimétrica é usado dois segredos, um para cifrar e outro para decifrar.
12 8 A criptografia simétrica é mais rápida e é usada para cifrar grandes quantidades de dados, como arquivos e comunicação entre computadores. A assimétrica é mais lenta e é mais usada para cifrar pequena quantidade de dados, como resumo ( hash ) de arquivos, que são usados na assinatura digital. A criptografia foi inventada na antigüidade e vem sendo usada e aprimorada até hoje. O principal uso da criptografia sempre foi as guerras. Os paises cifravam os dados para que os inimigos não os pudesse ler e então descobrir os segredos bélicos. Logo, sempre foi de grande interesse estudar estes mecanismos, tanto para construir algoritmos bons para se defender dos inimigos quanto para conseguir decifrar os dados do inimigo. A ciência que faz análise desses algoritmos é chamada de criptoanálise. O processo de inventar novos algoritmos e descobrir suas falhas acontece até hoje. O algoritmo simétrico mais usado hoje em dia é o DES, Data Encription Standard. A maioria dos sistemas de segurança têm ele como principal algoritmo. Ele foi estudado por vários anos por cientistas e foram descobertas várias falhas. Diante disso, foi necessário inventar outro algoritmo, que fosse mais seguro. Para isso, o NIST, National Institute of Standards and Tecnology, a agência responsável pela padronização de tecnologias da indústria americana, no ano 2000, fez um concurso para eleger um algoritmo para substituir o DES. As principais características dos candidatos analisadas foram: Segurança geral: resistente contra os ataques já conhecidos; Custo: o algoritmo deverá estar disponível mundialmente e livre de taxas; Computacionalmente eficiente: o algoritmo deverá ser rápido tanto em implementações em software e hardware; Pouco uso de memória: o algoritmo deverá usar pouca memória, pois ele poderá ser implementado em hardware com pouca memória RAM disponível, como os smart cards; Flexibilidade: disponibilidade de diferentes tamanhos de bloco e chave e diferentes modos de operação;
13 9 Simplicidade: o projeto do algoritmo deve ser simples, o que facilita a sua implementação e análise. Vários algoritmos foram submetidos ao processo de seleção. Os que chegaram à fase final foram: 1. MARS; 2. RC6; 3. Rijndael; 4. Serpent; 5. Twofish. O algoritmo chamado Rijndael foi escolhido para se tornar o novo algoritmo padrão, que foi batizado de AES, Advanced Encryption Standard. Ele foi criado por dois criptoanalistas belgas chamados Joan Daemen and Vincent Rijmen. Diferente dos algoritmos utilizados anteriormente, o Rijndael tem como base a matemática. Ela provê um maior formalismo ao algoritmo, permitindo provar matematicamente a eficácia dos mecanismos utilizados. Outra vantagem é que, por essas técnicas já terem sido profundamente estudadas, não é necessário criar toda uma nova gama de técnicas de análise específicas para ele, é possível utilizar o embasamento teórico relativo à matemática utilizada. Com o novo algoritmo definido, a pesquisa de criptografia simétrica está concentrada em analisá-lo. Alguns ataques já foram descobertos e dentre eles o mais eficaz é ataque quadrado. Esse trabalho de conclusão de curso tem como objetivo analisar as diferentes versões do ataque quadrado ao AES. Essa análise é composta pelo entendimento do ataque, a implementação computacional e observações sobre os resultados. O trabalho está estruturado em seis capítulos. No segundo capítulo são apresentados os fundamentos matemáticos utilizados pelo algoritmo. O terceiro capítulo explica o funcionamento do AES. O quarto capítulo apresenta o ataque quadrado e as suas diferentes versões. Finalmente, no quinto capítulo é apresentada a conclusão do trabalho.
14 Capítulo 2 Fundamentos Matemáticos O algoritmo criptográfico AES é um conjunto de passos que faz operações sobre um bloco de dados. Cada bloco nada mais é do que um conjunto de números. Para o projeto do Rijndael, foram empregadas teorias matemáticas relacionadas com conjuntos e operações sobre números, que são: aritmética em corpos de Galois, aritmética polinomial e aritmética modular. Elas serão explicadas nas sessões seguintes, de acordo com [2]. 2.1 Aritmética Modular Dado dois inteiros a e b, se nós dividirmos a por b, teremos o quociente inteiro q e um resto inteiro r, que obedecem à seguinte relação: a = qn + r 0 r < n; q = a/n o resto de a dividido por b. O resto r é também conhecido como resíduo. Se a é um inteiro e n é um inteiro positivo, definimos a mod b como Dois inteiros a e b são ditos ser congruentes módulo n, (a mod n) = (b mod n). Sua notação é a b mod n. se que n: Definimos Z n como o conjunto de inteiros não negativos menores Z n = 0, 1,..., (n 1)
15 11 Esse conjunto é referenciado como o conjunto de resíduos, ou classes de resíduos módulo n. Mais precisamente, cada inteiro de Z n representa uma classe de resíduos. Todos números congruentes entre si módulo n pertencem a mesma classe de resíduos. Se for efetuado aritmética modular em Z n, as seguintes propriedades serão seguidas para os inteiros de Z n : Propriedade Comutatividade Associatividade Distributividade Identidades Inversa aditiva Expressão (w + x)mod n = (x + w)mod n (w x)mod n = (x w)mod n [(w + x) + y]mod n = [w + (x + y)]mod n [(w x) y]mod n = [w (x y)]mod n [w (x + y)]mod n = [(w x) + w y]mod n [w + (x y)]mod n = [(w + x) + w + y]mod n (0 + w)mod n = w mod n (1 w)mod n = w mod n P ara cada w Z n, existe um z tal que w + z 0 mod n Tabela 2.1: Propriedades da Aritmética Modular A existência de uma inversa multiplicativa depende da condição de que o número a ser invertido deve ser relativamente primo ao número com o qual está calculando o módulo, isto é, dado um número a e deseja-se calcular seu inverso módulo um número n, a 1 só existirá se a for relativamente primo a n. Dois números são relativamente primos se eles só tiveram o número 1 como divisor comum. 2.2 Aritmética em Corpos de Galois Na álgebra abstrata, as operações são feitas entre elementos que pertencem a um mesmo conjunto. O resultado dessas operações deverá pertencer ao mesmo conjunto dos operadores. Quais operações satisfazem essa regra dentro de um conjunto vai depender das propriedades do conjunto. Sendo S um conjunto e uma operação qualquer definida para esse conjunto, as suas possíveis propriedades são: 1. Fechamento: se a e b pertencem a S, então a b também pertence a S; 2. Associatividade: a (b c) = (a b) c, para todo a,b e c pertencentes a S;
16 12 3. Elemento Identidade: existe um elemento e pertencente a S, tal que a e = e a para todo a pertencente a S; 4. Elemento Inverso: para cada a pertencente a S, existe um elemento a também pertencente a S, tal que a a = a a = e; 5. Comutatividade: a b = b a para todo a e b pertencentes a S. Quando duas operações estão envolvidas, como e (que também pode ser representada pela concatenação dos operadores), existe outra propriedade: 6. Distributividade: a(b c) = ab ac e (a b)c = ac bc para todo a,b e c pertencentes a S. Para esses conjuntos foram desenvolvidos importantes elementos matemáticos conhecidos como grupos, anéis e corpos. Cada um deles é denotado pelo conjunto de elementos, as operações definidas para esse conjunto e também pela gama de propriedades seguidas. O grupo G, denotado por G,, é um conjunto de elementos com uma operação binária, denotada por, que associa a cada par (a, b) de elementos pertencentes a G um novo elemento (a b) também pertencente a G. São obedecidas as propriedades de fechamento, associatividade, elemento identidade e o elemento inverso. Um exemplo de grupo é (N, +), na qual N é o conjunto dos números naturais e + é a operação de adição. Se um grupo tem um número finito de elementos, ele é chamado de grupo finito e a sua ordem é igual ao número de elementos. Caso contrário, ele é dito ser um grupo infinito. Um anél R, denotado por R, +,, é um conjunto de elementos com duas operações binárias + e, chamadas de adição e multiplicação. Em relação à +, são obedecidas todas as propriedades de um grupo mais a comutatividade. Já em relação a, apenas as propriedades de fechamento, associatividade e distributividade são seguidas. O anél é um conjunto com o qual é possível fazer adição, subtração ( soma de um operando com o inverso aditivo do outro) e multiplicação sem sair do conjunto. Um corpo F, denotado por F, +,, é um anél que também segue as propriedades comutatividade,não divisão por zero, elemento identidade e elemento
17 13 inverso em relação à. Os conjuntos dos números racionais, reais e complexos são exemplos de corpos. Esses são exemplos de corpos infinitos, a criptografia há interesse apenas nos corpos de ordem finita. Como os dados cifrados também precisam ser decifrados, é necessário que as operações executadas durante a cifragem sobre o conjunto de dados de entrada, o bloco, sejam inversíveis para que possa ocorrer a decifragem. A existência da inversibilidade dentro de um conjunto usando as operações de adição e multiplicação é garantida apenas pelos corpos. Um corpo finito de ordem p é um conjunto Z p de inteiros 0, 1,..., p 1, junto com operações matemáticas módulo p. Ele é denotado por GF (p),onde GF significa Galois Field em honra do matemático quem primeiro estudou o assunto. Como observado na sessão anterior, um elemento de Z p só vai ter uma inversa multiplicativa se ele for relativamente primo a p. Se p for primo, então todos os elementos não zero de Z p serão relativamente primos a ele e todos terão inversos multiplicativos. Para achar a inversa multiplicativa de um número dentro de um corpo, deve ser usado o algoritmo de Euclides. O AES usa polinômios no qual os coeficientes estão contidos em Z p e os polinômios são definidos módulo um polinômio m(x) de ordem n. 2.3 Aritmética Polinomial No AES são feitas operações modulares com polinômios. Os coeficientes desses polinômios fazem parte de um corpo finito. Desse modo é possível fazer divisão entre polinômios, uma vez que a divisão entre dois polinômios é uma multiplicação de um polinômio pelo inverso do outro. Em analogia à aritmética inteira, nós podemos escrever f(x) mod g(x) como sendo o polinômio r(x), proveniente do resto da divisão de f(x) por g(x). Para o projeto do AES, foi utilizado polinômios sobre GF (2), isto é, os coeficientes variam entre 0 e 1. Isso é de grande valia, pois a operação de
18 14 adição fica equivalente a operação ou-exclusivo e a multiplicação à E. Ela são extremamente rápidas de serem efetuadas em computadores. Um polinômio f(x) sobre um corpo F é chamado de irredutível se e somente se f(x) não poder ser expressado como produto de dois polinômios, ambos sobre F, e ambos com grau menor que f(x). Polinômios irredutíveis também podem ser chamados de polinômios primos. Na aritmética modular, é usado um corpo finito da forma GF (2 n ). Fazer operações polinomiais nesse tipo de corpo significa que os coeficientes vão variar de 0 a 1 e que os polinômios terão grau de até n 1. Isso acontece porque as operações polinomiais são feitas módulo um polinômio irredutível de grau n. Todos os corpos finitos de uma dada ordem são isomórficos, isto é, mesmo mudando o polinômio irredutível usado no operação modular, mas mantendo sua ordem, os elementos do corpo serão os mesmos. Um polinômio f(x) em GF (2 n ) n 1 f(x) = a n 1 x n 1 + a n 2 x n a 1 x + a 0 = a i x i pode ser representado unicamente pelos seus coeficientes binários (a n 1 a n 2...a 0 ). Portanto, um polinômio em GF (2 n ) pode ser representado por um número binário de tamanho n. A adição de polinômios corresponde a somar os coeficientes correspondentes, e, no caso de polinômios em Z 2, adição é apenas a operação ou-exclusivo. Então, a adição entre dois polinômios em GF (2 n ) corresponde a um operação ouexclusivo bit a bit. A multiplicação não é tão simples quanto a adição, mas existe um técnica que a simplifica bastante. Essa técnica será explicada com referência a GF (2 8 )usando o polinômio x 8 + x 4 + x 3 + x + 1, que é o corpo finito usado no AES. A multiplicação de dois polinômios consiste em várias multiplicações do primeiro operando por x e em somas dos resultados intermediários,por exemplo: i=0 (x 3 +x 2 +1) (x 2 +x+1) = ((x 3 +x 2 +1) x)+((x 3 +x 2 +1) x)+((x 3 +x 2 +1) x)+(x 3 +x 2 +1)
19 15 A multiplicação de um polinômio por x dentro do corpo finito especificado anteriormente pode ser implementada como um deslocamento de 1 bit a esquerda seguido de um ou-exclusivo bit a bit com o número , que representa o polinômio x 4 + x 3 + x + 1. Essa técnica é baseada no fato de que x 8 mod x 8 + x 4 + x 3 + x + 1 = x 4 + x 3 + x + 1. Se o resultado da multiplicação de dois polinômios for um polinômio de grau 8, isto é, o oitavo coeficiente foi igual a 1, então é feito o deslocamento e o ou-exclusivo com o , caso o polinômio resultante seja de grau inferior a 8, apenas o deslocamento é realizado.
20 Capítulo 3 O AES O AES é um algoritmo constituído por várias rodadas. Cada rodada é composta por 4 transformações, uma de permutação e três de substituição: 1. ByteSub: usa uma tabela de substituição para substituir byte por byte do bloco; 2. ShiftRow: uma permutação simples através deslocamento de linhas; 3. MixColumn: uma substituição que usa aritmética sobre GF (2 8 ); 4. AddRoundKey: aplicação de ou-exclusivo entre o bloco e a chave. O número de rodadas é variável e dependente do tamanho da chave. São 10 rodadas para chave de 128 bits, 12 para 192 bits e 14 para 256 bits. A última rodada não contém a transformação MixColumn, que foi retirada para que fosse possível montar o algoritmo inverso ao AES, que é usado na decifragem. A estrutura do AES inverso pode ser visualisada na figura 3.1. Antes da primeira rodada é feita uma AddRoundKey. Apenas a AddRoundKey faz uso da chave. Qualquer outra operação, aplicada no fim ou no começo, é reversível sem conhecimento da chave e portanto, não adiciona segurança ao algoritmo. A seqüência de passos pode ser visualizada na figura 3.1. Nas sessões seguintes serão explicadas as transformações e o algoritmo de derivação de chave. O apêndice A contém o código fonte da implementação do AES, que foi baseada na implementação oferecida pelo NIST [3].
21 17 Figura 3.1: Estrutura do AES 3.1 ByteSub Essa transformação consiste em substituir cada byte do bloco por outro byte, que é obtido consultando a caixa-s. Ela é uma matriz que contém todos os 256 possíveis valores de 8 bits. O mapeamento dos bytes é feito da seguinte maneira: os primeiros
22 4 bits do byte são usados como valor da linha da matrix e os outros 4 bits como valor para a coluna. A figura 3.2 ilustra essa substituição. 18 Figura 3.2: ByteSub [1] Essa transformação provê a não linearidade do cifrador. A caixa-s é derivada da função inversa sobre GF (2 8 ), conhecida por ter boas propriedades nãolineares. Essa função pode ser representada por uma função algébrica muito simples, o que permite fazer manipulações algébricas facilmente. Essa maniputações podem ser usadas para montar ataques como os ataques de interpolação. Para contornar isso, essa função é combinada com uma transformação affine inversível simples. As duas funções combinadas formam uma expressão algébrica complexa, que inibe os ataques [4]. A construção da caixa-s é descrita nos seguintes passos: 1. A caixa-s é inicializada com valores de bytes seguindo uma seqüência ascendente linha por linha. A primeira linha contém os valores 00, 01,..., 0F ; a segunda contém 10, 11,..., 1F ; e assim por diante; 2. Cada byte na caixa-s é mapeado para o seu inverso multiplicativo no corpo finito GF (2 8 ); 3. É aplicada uma transformação affine particular. Essa transformação foi escolhida de modo. Dado um byte rotulado como b 7 b 6 b 5 b 4 b 3 b 2 b 1 b 0, a operação escolhida foi: b i = b i b (i+4)mod 8 b (i+5)mod 8 b (i+6)mod 8 b (i+7)mod 8 c i (3.1)
23 19 onde c i é um i-ésimo bit da constante e o sinal ( ) significa que a variável será atualizada com o valor da direita. Ela também pode ser representada pela multiplicação das matrizes: b 0 b 1 b 2 b 3 b 4 b 5 b 6 b 7 = b 0 b 1 b 2 b 3 b 4 b 5 b 6 b (3.2) Para a decifragem é usada a operação InvSubBytes, que é semelhante a SubByte, porém usa uma caixa-s inversa. Essa caixa-s inversa é contruída aplicando o inverso multiplicativo no corpo finito GF (2 8 ) à caixa-s usanda na cifragem em conjunto da transformação affine inversa: b i = b (i+2)mod 8 b (i+5)mod 8 b (i+7)mod 8 d i onde d é Cuja representação matricial é: b 0 b 1 b 2 b 3 b 4 b 5 b 6 b 7 = b 0 b 1 b 2 b 3 b 4 b 5 b 6 b (3.3)
24 ShiftRow Essa transformação consiste em deslocalar as linhas do bloco ciclicamente para a esquerda. O número de deslocamentos varia de acordo com a linha. A primeira linha não é deslocada, a segunda é deslocada uma posição, a segunda duas e a terceira posições. Dessa forma, cada coluna do bloco de saída é composta por bytes de todas as colunas do bloco de entrada. A figura 3.3 ilustra essa transformação. Figura 3.3: ShifRow [1] A transformação inversa à ShiftRow é chamada de InvShiftRow. Ela é semelhante à ShiftRow, porém o sentido do deslocamento é o inverso, para a direita. 3.3 MixColumn Essa transformação opera em cada coluna individualmente. Cada byte da coluna é mapeado a um novo valor que é uma função de todos os quatro bytes da coluna (Figura 3.4). A tranformação pode ser definida através da multiplicação das matrizes: s 0,0 s 0,1 s 0,2 s 0,3 s 0,0 s 0,1 s 0,2 s 0, s 1,0 s 1,1 s 1,2 s 1,3 s = 1,0 s 1,1 s 1,2 s 1, s 2,0 s 2,1 s 2,2 s 2,3 s 2,0 s 2,1 s 2,2 s 2, s 3,0 s 3,1 s 3,2 s 3,3 s 3,0 s 3,1 s 3,2 s 3,3 Cada elemento da matrix resultante é a soma do produto dos elementos de uma linha e uma coluna. As adições e as multiplicações são feitas em
25 21 Figura 3.4: MixColumn [1] GF (2 8 ). A transformação MixColumn em uma coluna é expressada como: s 0,j = (2 s 0,j ) (3 s 1,j ) s 2,j s 3,j s 1,j = s 0,j (2 s 1,j ) (3 s 2,j ) s 3,j s 2,j = s 0,j s 1,j (2 s 2,j ) (3 s 3,j ) (3.4) s 3,j = (3 s 0,j ) s 1,j s 2,j (2 s 3,j ) Essa transformação está fundamentada em multiplicações de polinômios. Cada elemento de uma coluna se transforma nos coeficientes de um polinômio, que então é multiplicado pelo polinômio c(x)(equação 3.5) módulo x sobre GF (2 8 ). c(x) = 03 x x x + 02 (3.5) Esse polinômio é coprimo a x e portanto inversível. 3.4 AddRoundKey Nesse passo a chave é combinada com o bloco. Para cada rodada é usada uma subchave diferente. As subchaves são obtidas através da chave mestra usando um algoritmo de derivação de chave. A junção do bloco com a subchave é feita com a operação ou-excluivo, mostrada pela Figura 3.5:
26 22 Figura 3.5: AddRoundKey [1] 3.5 Derivação de chave O algoritmo de derivação de chave usado na AES consiste em uma fase de expanção e outra de seleção. Na fase de expanção a chave mestra de 128 bits é expandida para uma chave de 1408 bits. Essa derivação é descrita pelo seguinte algoritmo na linguagem C: KeyExpansion(byte MasterKey[16], word W[44]) for(i = 0; i < 4; i++) W[i] = (MasterKey[4*i],MasterKey[4*i+1],MasterKey[4*i+2],MasterKey[4*i+3]); for(i = 4; i < 44; i++) temp = W[i - 1]; if (i % 4 == 0) temp = SubByte(RotByte(temp)) ^ Rcon[i / 4]; W[i] = W[i - 4] ^ temp; Nesse algoritmo, W é um array de palavras (32 bits). A operação RotByte faz uma permutação cíclica da entrada, por exemplo, uma palavra (a,b,c,d)
27 23 se tranforma em (b,c,d,a). Rcon é um conjunto de constantes que são adicionadas às subchaves. Para cada subchave, uma constante diferente é adicionada, o que previne a criação de chaves fracas, como acontecia no DES. Na derivação de chave do DES era possível criar chaves de modo que a cifragem e a decifragem produzissem resultados iguais. A figura 3.6 ilustra os passos: ByteSub RC Figura 3.6: Derivação de chave A fase de seleção é simples. As subchaves são retiradas da chave expandida sequencialmente, a primeira subchave é composta do bit 0 até bit 127, a segunda subchave do bit 128 até o 255, e assim por diante. A execução do algoritmo produziria os seguintes passos: W[0] = (MasterKey[0],MasterKey[1],MasterKey[2],MasterKey[3]) W[1] = (MasterKey[4],MasterKey[5],MasterKey[6],MasterKey[7]) W[2] = (MasterKey[8],MasterKey[9],MasterKey[10],MasterKey[11]) W[3] = (MasterKey[12],MasterKey[13],MasterKey[14],MasterKey[15]) W[4] = SubByte(RotByte(W[3])) ^ W[0] ^ Rcon[1]
28 24 W[5] = W[4] ^ W[1] W[6] = W[5] ^ W[2] W[7] = W[6] ^ W[3]... W[40] = SubByte(RotByte(W[39])) ^ W[36] ^ Rcon[10] W[41] = W[40] ^ W[37] W[42] = W[41] ^ W[38] W[43] = W[42] ^ W[39] O algoritmo de derivação de chave foi montado de forma que é possível restaurar a chave mestra através de qualquer subchave. Para isso, é necessário seguir o caminho inverso da derivação. A chave mestra corresponde aos primeiros 128 bits da chave estendida. O algoritmo inverso é: InverseKeyExpansion(byte SubKey[16], word W[4*NUMERO_DE_RODADAS], MasterKey[16]) for(i = 0,j = 4*NUMERO_DE_RODADAS; i < 4; i++,j++) W[j] = (SubKey[4*i],SubKey[4*i+1],SubKey[4*i+2],SubKey[4*i+3]); for(j -= 5; j >= 0; j--) if (j % 4 == 0) W[j] = ByteSub(RotByte(W[j+3])) ^ W[j+4]; W[j] ^= Rcon[j / 4]; else W[j] = W[j+3] ^ W[j+4]; for(i = 12,j = 3; i >= 0; i-=4,j--) (MasterKey[i],MasterKey[i+1],MasterKey[i+2],MasterKey[i+3]) = w[j] passos: A execução do algoritmo usando 10 rodadas produziria os seguintes
29 25 W[43] = (Subkey[12],Subkey[13],Subkey[14],Subkey[15]) W[42] = (Subkey[8],Subkey[9],Subkey[10],Subkey[11]) W[41] = (Subkey[4],Subkey[5],Subkey[6],Subkey[7]) W[40] = (SubKey[0],Subkey[1],Subkey[2],Subkey[3]) W[36] = SubByte(RotByte(W[39])) ^ W[40] ^ Rcon[10] W[37] = W[40] ^ W[41] W[38] = W[41] ^ W[42] W[39] = W[42] ^ W[43]... W[3] = (Subkey[12],Subkey[13],Subkey[14],Subkey[15]) W[2] = (Subkey[8],Subkey[9],Subkey[10],Subkey[11]) W[1] = (Subkey[4],Subkey[5],Subkey[6],Subkey[7]) W[0] = (Subkey[0],Subkey[1],Subkey[2],Subkey[3]) em [5] e [4]. Maiores detalhes sobre o projeto do AES podem ser encontrados
30 Capítulo 4 O Ataque Quadrado O ataque quadrado é uma técnica muito efetiva de criptoanálise para cifradores de bloco. Ele foi concebido como uma técnica dedicada ao algoritmo Square, mas também pode ser usada nos cifradores Rijndael (AES), Twofish e IDEA. Ele é o melhor ataque conhecido contra o AES. Diferentes versões desse ataque foram desenvolvidas, variando a ordem do ataque e o número de rodadas do cifrador. A ordem do ataque diz respeito ao número de bytes do bloco que são saturados. Serão analisados os ataques de primeira ordem para 4 rodadas [6] e 6 rodadas [7] e o ataque de quarta ordem para 5 rodadas [8]. Nas sessões seguintes serão mostradas as diferentes versões do ataque quadrado que foram analisadas nesse trabalho. O apêndice A contém os códigos fonte das implementações dos ataques. Devido a limitações de capacidade de processamento e tempo, o ataque de primeira ordem sobre 6 rodadas e o ataque de quarta ordem sobre 5 rodadas foram implementados em cima de uma versão reduzida do AES. Essa versão tem a metade do tamanho de bloco e chave e é orientada a nibble(4 bits), ao invés de byte. O projeto desse mini-aes está fora do escopo desse trabalho. O ataque implementado sobre esse algoritmo tem os mesmos princípios que o implementado sobre o AES padrão, porém a complexidade do ataque é muito menor, o que torna a sua implementação viável.
31 Ataque de primeira ordem sobre 4 rodadas A descrição desse ataque é baseada em [6]. cifrador: Considere a representação matricial 4 4 do bloco de entrada do a 0,0 a 0,1 a 0,2 a 0,3 a 1,0 a 1,1 a 1,2 a 1,3 a 2,0 a 2,1 a 2,2 a 2,3 a 3,0 a 3,1 a 3,2 a 3,3 (4.1) O ataque consiste em criar um conjunto de 256 blocos que são diferentes entre si em apenas uma posição, no elemento a 0,0. Essa posição assume todos os valores possíveis de um byte, de 0 até 255, cada bloco com um valor. As outras 15 posições assumem o mesmo valor em qualquer bloco do conjunto. Posições diferentes podem ter valores distintos, o que se mantém constante é o valor em cada posição específica. Esse conjunto se chama conjunto integral ou conjunto Λ. A posição que assume os valores diferentes se chamada posição saturada ou ativa, e é representada pela letra p, de permutação. As posições que não têm o valor mudado são representadas pela letra c, de constante. A representação do bloco fica assim: p c c c c c c c c c c c c c c c i : i = 0, 1,..., 255 (4.2) Nas subsessões seguinte serão mostradas as transformações que o conjunto integral sofre durante as 4 rodadas da cifragem. Para tal, os quatro blocos: de texto em claro serão tidos como exemplo para mostrar a evolução dos blocos durante a cifragem. A chave usada será: C D A 0E B 0F
32 Tanto a escolha dos quatro blocos de texto quanto a escolha da chave não tiveram motivo em especial. Esses dados podem ser escolhidos aleatoriamente a Rodada A aplicação inicial de AddRoundKey não altera a estrutura do conjunto integral, apenas muda o valor das posições constantes e muda a ordem dos valores da posição saturada, que continua tendo todos os 256 valores dentro do conjunto: AB 23 AB 23 AB 23 AB 23 AB 23 AB 23 AB 23 AB 45 CD 45 CD 45 CD 45 CD 45 CD 45 CD 45 CD 45 CD 67 EF 67 EF 67 EF 67 EF 67 EF 67 EF 67 EF 67 EF 28 A ordem dessas valores não importa, pois trata-se de um conjunto e não de uma sequência ordenada. A transformação ByteSub é uma função injetora, o que faz com que a sua aplicação ao conjunto integral não altere a estrutura do conjunto. A posição saturada sofrerá apenas uma permutação e as posições constantes terão seus valores trocados: p c c c c c c c c c c c c c c c i : i = 0, 1,..., 255 (4.3) O estado dos blocos fica: 7C A7 7C A7 63 A7 7C A7 7B A7 7C A7 77 A7 7C A E BD 6E BD 6E BD 6E BD 6E BD 6E BD 6E BD 6E BD 85 DF 85 DF 85 DF 85 DF 85 DF 85 DF 85 DF 85 DF A transformação ShiftRow apenas troca a localização dos bytes: 7C A7 7C A7 63 A7 7C A7 7B A7 7C A7 77 A7 7C A E BD 6E BD 6E BD 6E BD 6E BD 6E BD 6E BD 6E BD DF 85 DF 85 DF 85 DF 85 DF 85 DF 85 DF 85 DF 85 Como a posição saturada usada é na primeira linha e ela não sofre deslocamento na transformação, nada é mudado. Mas se a posição saturada fosse
33 em outra linha, ela seria deslocada, mas isso nada afeta a estrutura do conjunto integral. A transformação MixColumn muda toda a coluna que contém a posição saturada. Isso faz com que os outros 3 bytes da coluna passem a ser função da posição saturada. Mas não faz com que a posição saturada pare de assumir os 256 valores possíveis. Para melhor explicar o efeito da MixColumn, a considere como sendo a função MC(x, y, z, w), onde x,y,z e w são as posições de uma coluna. No caso da primeira coluna, a MC vai receber como parâmetro uma permutação e três constantes: MC(p,c,c,c). Como apenas o parâmetro p muda entre os blocos, o resultado do MC vai depender apenas de p. Variando todos os valores possíveis das entradas, , o conjunto imagem será igual a p. Nas posições onde os quatro parâmetros são constantes, M C(c, c, c, c), a imagem será uma constante: MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) Os blocos se tornaram: EF 07 EF 07 D1 07 EF 07 E1 07 EF 07 F9 07 EF 07 D5 B2 D5 B2 CA B2 D5 B2 D2 B2 D5 B2 DE B2 D5 B2 B8 74 B8 74 A7 74 B8 74 BF 74 B8 74 B3 74 B8 74 2D 78 2D 78 0C 78 2D D D 78 i 29 p c c c p c c c : i = 0, 1,..., 255 p c c c p c c c i (4.4) A transformação AddRoundKey, como foi dito anteriormente, não altera a estrutura do conjunto integral, apenas faz uma permutação da posição saturada: 8D EC B3 EC EC B EC B 87 C3 0F C3 0F 4C 87 C3 0F C3 0F AA AB 3D 23 AA AB AA AB AA AB ED DF CC DF E DF F DF a Rodada A transformação ByteSub apenas muda o valor de cada byte, mantendo a estrutura do conjunto: 5D CE 6B 43 6D CE 6B 43 EC CE 6B CE 6B 43 B3 17 2E E E E AC AC 62 3F 26 AC 62 A5 26 AC B 4D 9E 4B 5B 4D 9E 69 5B 4D 9E 8C 5B 4D 9E
34 A trasformação ShiftRow desloca as posições saturadas, fazendo com que toda coluna contenha uma posição saturada: 30 p c c c c p c c c c p c c c c p i : i = 0, 1,..., 255 (4.5) 5D CE 6B 43 6D CE 6B 43 EC CE 6B CE 6B E 76 B3 17 2E E E AC AC AC 62 3F 26 AC 62 A5 26 9E 55 5B 4D 9E 4B 5B 4D 9E 69 5B 4D 9E 8C 5B 4D A trasformação MixColumn opera sobre cada coluna separadamente e faz com que todas as posições do bloco se tornem saturadas: p p p p p p p p p p p p p p p p i : i = 0, 1,..., 255 (4.6) B1 C D1 DC 30 8D C8 FE B B2 F F B5 24 B3 5D 9D 36 4B B B0 DB CD 6B 80 F9 BE F8 01 9F 8E F1 F9 AB A1 D1 7B AF EE CA 2B 93 5A 59 B3 D A0 06 D8 70 Como foi dito anteriormente, a transformação AddRoundKey não muda a estrutura do conjunto. Portanto, depois de duas rodadas do AES, cada um dos 16 bytes de cada bloco está saturado. AB 33 9F 5B CB 2D 2B F5 D2 0F 33 EE 39 EA A9 8E A 96 BA B3 68 BE A8 4B 8D 0B E8 76 4A 4E D A4 C7 0E 0D AD 3F 3A 22 8D 40 BB B A2 88 C3 1E AB 9B B a Rodada Foi visto no passo anterior que as transformações ByteSub, Shift- Row e AddRoundKey não alteram a estrutura do conjunto integral. O mesmo não acontece com a transformação MixColumn. A MixComlumn faz com que cada posição da coluna seja função das quatro posições. Se apenas uma posição estiver saturada, todos os valores dos
35 elementos vão variar de acordo com a posição saturada. Como um elemento saturado pode ter 2 8 valores, os outros três valores também vão variar nessa faixa. Até a segunda rodada existia no máximo um elemento saturado em cada posição da coluna, o que fazia com que a conjunto integral não perdesse sua estrutura. Mas nessa rodada, todos os elementos das colunas estão saturados. Logo, cada elemento de uma coluna tem como valor o resultado da MC com os quatro parâmetros variando: MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) i 31 b b b b b b b b : i = 0, 1,..., 255 b b b b b b b b i (4.7) A variação dos quatro valores, ( ), resulta em 2 32 possíveis combinações. Essa combinações retornam 2 32 resultados, sendo 2 8 valores distintos distribuidos de forma não uniforme. Como existe apenas 2 8 blocos, resultados não aparecerão, apenas os primeiros 2 8. Como a distribuição dos valores dos resultados não é uniforme, vai acontecer de valores aparecerem repetidos e outros valores não aparecem. Logo, a estrutura do conjunto integral é perdida. Nessa rodada, apesar da estrutura do conjunto integral ter sido quebrada, existe uma propriedade que não é afetada por transformações lineares e será usada como base para o ataque. Essa propriedade é o balanço, que é a soma dos elementos de mesma posição do conjunto integral. A seguinte equação formaliza esse conceito: a 0 i,j a 1 i,j... a 255 i,j 255 a k i,j = 0 (4.8) O somatório é o ou-exclusivo dos termos. Em qualquer posição do bloco cada bit assume o valor 1 exatamente 128 vezes, fazendo com que a aplicação do ou-exclusivo resulte em 0 bit a bit. Logo, todas as posições do conjunto integral estão balanceadas. Quanto à transformação AddRoundKey, ela também não altera o balanço, pois a mesma subchave é aplicada a todos os blocos do conjunto. Portanto, depois de 3 rodadas do AES, todas as posições dos blocos estão balanceada. Os estado dos blocos exemplares depois da ByteSub, ShiftRow, MixColumn e AddRoundKey, respectivamente, são: 62 C3 DB 39 1F D8 F1 E6 B5 76 C D D D6 90 F4 6D 45 AE C2 B3 5D 2B 9B 38 D6 2F 9A 5A C6 AB D D k=0
36 32 09 EA 37 C7 CA 17 6F 3A C4 2E C9 5F 3D 62 C3 DB 39 1F D8 F1 E6 B5 76 C D D D6 90 F AE C2 6D 5D 2B 9B B3 2F 9A 38 D A 45 D7 95 C6 AB 93 5D C7 09 EA 37 3A CA 17 6F 62 C4 2E 72 3D 14 C9 5F 4C A B3 98 0B E 6D 21 B C FB F2 FB 00 3F B 22 A8 A0 4E A0 C9 9F 88 FE E3 BE E4 9E 35 2A E2 50 3C A A 82 CC 09 A B9 8D C 1F 1E B0 D7 B9 78 C5 48 A4 DE B9 0B 43 B1 8D A7 C2 75 2E 7F A4 71 5D F E C A E6 3F 19 FC D7 BB B0 23 B6 47 BD 15 A1 C9 6E 05 5F C a Rodada Essa rodada é a última nesse ataque e portanto consiste apenas nas transformações ByteSub, ShiftRow e AddRoundKey. Considerando h como o resultado do terceiro passo, o quarto passo pode ser representado pela seguinte equação: z ShiftRow(ByteSub(h)) K 4 (4.9) onde K 4 é a subchave utilizada no quarto passo. É possível escrever o resultado do terceiro passo da seguinte maneira: h = InvByteSub(InvShiftRow(z K 4 )) = InvByteSub(InvShiftRow(z) InvShiftRow(K 4 )) (4.10) Esse processo pode ser visualizado pela figura B.1. Como foi visto anteriormente, todas as posições de h são balanceadas. Logo, para a subchave K 4 correta, todas as posições de h (Equação B.9) são balanceadas. Caso a subchave seja incorreta, o balanço em uma posição qualquer será incorreto, isto é, diferente de zero. Uma subchave incorreta pode produzir um balanço correto com a probabilidade de 1, pois existem 256 valores possíveis para 256 um byte e o zero é um deles. O ataque quadrado está baseado nas observações acima e se re-
37 Figura 4.1: Ataque 4 rodadas 33
38 sume em buscar exaustivamente a chave usada na cifragem testando a sua corretude através do balanço do conjunto integral. 34 O ataque começa com a obtensão dos blocos do conjunto integral cifrados. Seja z k o k-ésimo bloco do conjunto integral cifrado. É fixado um byte zi,j k e tenta-se encontrar o valor ki,j, 4 que é o byte da subchave usado na cifragem desse bloco. Para isso, primeiro é dado um valor aleatório a ki,j 4 e depois é feita a transformação InvShiftRow sobre zi,j k e ki,j, 4 e em seguida é aplicado InvByteSub sobre o ou-exclusivo desses dois resultados. Repete-se o processo para todos os blocos do conjunto integral, calcula-se o ou-exclusivo dos resultados e testa-se se a soma é zero. A operação InvShiftRow pode ser contornada da seguinte forma: [InvShiftRow(z k )] i,j = z k i,(4 i+j)mod 4 (4.11) o que resume a procura do byte da subchave a verificar se a seguinte igualdade é válida: 255 k=0 S 1 [z k i,(4 i+j)mod 4 k i,j ] = 0 (4.12) onde S 1 é a caixa-s inversa. Se a igualdade for válida, o valor de k 4 i,j está certo, caso contrário, o valor de k 4 i,j está errado e é dado um novo valor para ele e todo o processo é repetido. Como foi dito anteriormente, esse teste pode retornar um valor errado com probabilidade de 1. O que pode ser feito é usar um segundo conjunto 256 integral no processo, o que diminui a chance de erro para Para obter o resto de K 4 basta repetir o procedimento para os outros bytes. Através desse ataque foi possível obter a subchave K 4. Para obter a chave mestra é necessário inverter o processo de derivação de chave, descrito na sessão 3.5. A complexidade desse ataque é equivalente a 2 15 ( ) cifragens usando 2 9 textos escolhidos. Esse resultado é obtido através da multiplicação do número de bytes da chave a serem encontrados(2 4 ) pela faixa de valores possíveis de um byte da chave(2 8 ), pelo número de indexações da caixa-s para cada byte da chave(2 8 ) e pelo número de vezes que tudo isso é feito(2), tudo divido pelo número
39 35 de indexações presentes em uma cifragem com 4 rodadas(2 6 ). complexidade = ((n o de bytes da chave) (faixa de valores da chave) (n o de indexacoes para cada tentativa de chave)) (n o de conjuntos integrais) (4.13) ((indexacoes por rodada) (n o de rodadas)) 4.2 Ataque de primeira ordem sobre 6 rodadas Esse ataque é basicamente o ataque sobre 4 rodadas com duas extenções, uma nova rodada no final do cifrador e a outra no início. Nas próximas sessões serão explicadas as extensões e como elas são combinadas para formar o ataque ao AES com 6 rodadas Extensão no final Essa extensão consiste em adicionar uma nova rodada no final do cifrador, que o deixa com 5 rodadas. O ataque é fundamentado sobre o mesmo princípio que o anterior, decifrar o texto cifrado até que os blocos estejam balanceados, o que é uma característica dos blocos cifrados com 3 rodadas. Portanto, nesse ataque é necessário decifrar duas rodadas do AES. Considerando h como o resultado da terceira rodada, z o resultado do quarta rodada e p o resultado da quinta rodada, é possível escrever h da seguinte maneira: h = InvByteSub(InvShiftRow(InvMixColumn(z)) InvShiftRow(InvMixColumn(K 4 ))) z = InvByteSub(InvShiftRow(p) InvShiftRow(K 5 )) (4.14) O processo pode ser visualizado pela figura B.2. Para que seja possível fazer as rodadas de decifragem, é necessário conhecer as subchaves empregadas em cada rodada. No caso do ataque, essas subchaves serão descobertas através de uma busca exaustiva. Para cada tentativa de recuperar o h corretamente, uma 5-tupla de bytes terá que ser adivinhada: um byte da subchave da quarta rodada e quatro bytes da subchave da quinta rodada
40 Figura 4.2: Estensão no final 36
41 37 pertencentes à mesma coluna. São necessários 4 bytes da quinta subchave, porque o resultado da InvMixcolumn depende dos 4 bytes da coluna. A equação que representa a relacão posicional entre um byte de h e cada byte da 5-tupla é: h i,j (K 4 i,(4 i+j)mod4, K 5 i,(8 2i+j)mod4, K 5 i+1,(8 2i+j)mod4, K 5 i+2,(8 2i+j)mod4, K 5 i+3,(8 2i+j)mod4) (4.15) A complexidade desse ataque é de 2 37,7 ( ( ) ) cifragens e 2 32 textos escolhidos. Esse número foi obtido pela seguinte equação: complexidade = ((n o de colunas da chave) (faixa de valores da coluna) ((n o de indexacoes na quinta rodada) + (faixa de valores de um byte da chave da quarta rodada) (4.16) (n o de indexaes na quarta rodada))) ((indexacoes por rodada) (n o de rodadas)) Extensão no início Nessa estensão, o ataque acima é extendido com mais uma rodada, mas dessa vez no início do algoritmo. Isso faz com que o ataque tenha eficácia sobre um AES de 6 rodadas. O conjunto de entrada deve ser escolhido de modo que o resultado da primeira rodada seja igual à entrada do ataque de 5 rodadas descrito anteriormente, isto é, um conjunto integral dos quais uma posição dos blocos deve ser uma permutação e as outra devem ser constantes. Para isso, é necessário usar um conjunto de entrada de 2 32 blocos com 4 posições saturadas. As posições dos elementos saturandos deve ser tal que, ao passar pela ShiftRow, eles pertencerão a mesma coluna. Essa coluna conterá o elemento saturado no final da rodada. Quando esses 2 32 blocos são cifrados pela rodada adicional, eles produzirem 2 32 blocos dos quais pode ser selecionado um conjunto integral. É possível selecionar 28 diferentes conjuntos integrais. Para fazer essa rodada inicial é preciso conhecer os 4 bytes da chave que irão ser combinados com as 4 posições saturadas. Esses bytes são atingidos
42 38 através de busca exaustiva. Para cada quadrupla de bytes testados, é necessário rodar o ataque anterior. A complexidade do ataque é ( ) cifragens e 2 32 textos escolhidos. Esse resultado é obtido através da multiplicação da faixa de bytes a serem testados nos 4 bytes da primeira subchave(2 32 ) pela complexidade do ataque anterior( ). Esse processo pode ser visualizado pela figura B.3. Figura 4.3: Extensão no início
43 Ataque de quarta ordem sobre 5 rodadas Esse ataque é composto pelos mesmos passos que o ataque de primeira ordem sobre 4 rodadas, mas com um conjunto de blocos de entrada diferente, um conjunto integral de quarta ordem. Isso significa que o conjunto contém quatro elementos saturados. Esses 4 bytes podem ser vistos como uma word que varia de 0 a Logo, para o conjunto integral conter todos os valores possíveis são necessários 2 32 blocos. Para explicar a importência desse ataque é necessário explicar o conceito de invariante. O invariante de um algoritmo é a parte do algoritmo cujo comportamento é possível prever, é a parte até a qual estrutura dos blocos de entrada não é perdida. O objetivo de um cifrador é acabar com qualquer estrutura que os blocos de entrada possam ter, fazendo com que a saída do cifrador seja semelhante a um gerador de números aleatórios. Logo, quanto menor o invariante de cifrador, melhor ele é. Com o uso de um conjunto integral de quarta ordem o invariante do cifrador avança mais uma rodada, permitindo extender o ataque ao AES a 5 rodadas. Esse avanço é possível porque o conjunto consegue passar pelo terceiro MixColumn sem perder a sua estrutura. As propriedades do MixColumn referente a isso foram explicadas na subsessão B A complexidade desse ataque é equivalente a ( ) cifragens usando 2 33 textos escolhidos. Esse resultado é obtido através da multiplicação do número de bytes da chave a serem encontrados(2 4 ) pela faixa de valores possíveis de um byte da chave(2 8 ), pelo número de indexações da caixa-s para cada byte da chave(2 32 ) e pelo número de vezes que tudo isso é feito(2), tudo divido pelo número de indexações presentes em uma cifragem com 5 rodadas(2 4.5). complexidade = ((n o de bytes da chave) (faixa de valores da chave) (n o de indexacoes para cada tentativa de chave)) (n o de conjuntos integrais) (4.17) ((indexacoes por rodada) (n o de rodadas))
44 Capítulo 5 Considerações Finais e Trabalhos Futuros Esse trabalho conseguiu atingir todos os objetivos definidos. Com os estudos feitos nesse trabalho foi possível por em prática as pesquisas feitas pelo Labsec na área de criptoanálise e expandir os conhecimentos sobre criptografia e suas fundamentações matemáticas. A dificuldade enfrentada no desenvolvimento das análises computacionais foi a grande complexidade dos algoritmos de criptoanálise, que requerem uma grande capacidade de processamento, as vezes até proibitiva. Alguns testes implementados podem demorar horas para serem concluídos. Não foi possível implementar ataques sobre um maior número de rodadas do AES, pois eles demandam uma grande capacidade de processamento e tempo, os quais não estavam disponíveis para o desenvolvimento desse trabalho. Esse trabalho pode ser expandido visando amenizar o problema apresentado a cima. As soluções possíveis são: Desenvolvimento de uma aplicação que distribua o processamento dos ataques entre vários computadores, tanto para processamento dedicado e não dedicado. Pesquisar ataques mais eficientes quanto ao uso de CPU e memória.
45 Referências Bibliográficas [1] WIKIPEDIA. Advanced Encryption Standard. July Disponível em: < [2] STALLINGS, W. Cryptography and Network Security - Principles and Pratice. [S.l.]: Alan Apt, [3] NIST. AES Implementation. Disponível em: < [4] RIJMEN, J. D. V. The Disign of Rijndael. [S.l.]: Springer-Verlag, [5] RIJNMEN, J. D. V. Aes proposal: Rijndael [6] BARRETO, P. O ataque quadrado. Disponível em: < [7] LUCKS, S. Attacking seven rounds of rijndael under 192-bit and 256-bit keys. AES Candidate Conference 2000, p , [8] PHAN, J. N. J. D. S. de F. R. C.-W. New multiset attacks on rijndael with large blocks. Mycrypt 2005, p , 2005.
46 Apêndice A Código Fonte #include <cstdio> #include <cstdlib> #include "RijndaelAPI.h" #include "RijndaelAlg.h" #include "conf.h" 1Order4Rounds.cpp extern void invertechave(rijndaelalg* rijndaelalg,byte subchave[4][8],byte chavemestra[4][key_length/32]); extern void geraconjuntointegral(byte conjunto[][block_length/8],unsigned int valorbytesnsaturados); extern void calculabalanco(byte conjunto[256][block_length/8],byte balanco[block_length/8]); extern bool balancocorreto(byte bytes[256]); int main(int argc,char* argv[]) bool debug = true; RijndaelAlg* rijndaelalg; RijndaelAPI* rijndaelapi; unsigned int i,j,x,t; //variáveis usadas para loops //necessário dois chars para representar um byte em hexadecimal char masterkey[key_length/4] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F ; //Constroi conjunto integral BYTE conjuntointegral1[256][block_length/8]; BYTE conjuntointegral2[256][block_length/8]; BYTE conjuntointegralcifrado1[256][block_length/8]; BYTE conjuntointegralcifrado2[256][block_length/8]; geraconjuntointegral(conjuntointegral1,0); geraconjuntointegral(conjuntointegral2,1);
47 43 rijndaelalg = new RijndaelAlg(userInterface,debug); rijndaelapi = new RijndaelAPI(rijndaelAlg,userInterface,debug); rijndaelapi->inicializa(dir_encrypt,mode_ecb,null,masterkey); //cifrando for(i = 0;i < 256;i++) rijndaelapi->cifrabloco(conjuntointegral1[i],conjuntointegralcifrado1[i]); for(i = 0;i < 256;i++) rijndaelapi->cifrabloco(conjuntointegral2[i],conjuntointegralcifrado2[i]); BYTE b1[256][4][8]; BYTE b2[256][4][8]; BYTE subkey5[4][8]; for (x = 0; x < 256; x++) for (j = 0; j < 4; j++) for(i = 0; i < 4; i++) b1[x][i][j] = conjuntointegralcifrado1[x][4*j+i] & 0xFF; b2[x][i][j] = conjuntointegralcifrado2[x][4*j+i] & 0xFF; for (x = 0; x < 256; x++) rijndaelalg->shiftrow(b1[x],1,4); rijndaelalg->shiftrow(b2[x],1,4); BYTE blockxorkey1; BYTE r1[256]; BYTE blockxorkey2; BYTE r2[256]; bool naoachouchave; for (j = 0; j < 4; j++) for(i = 0; i < 4; i++) subkey5[i][j] = 0; naoachouchave = true; while(naoachouchave) for(t = 0;t < 256;t++) blockxorkey1 = b1[t][i][j] ^ subkey5[i][j]; blockxorkey2 = b2[t][i][j] ^ subkey5[i][j]; r1[t] = rijndaelalg->inversesbox(blockxorkey1); r2[t] = rijndaelalg->inversesbox(blockxorkey2); if(balancocorreto(r1) && balancocorreto(r2))naoachouchave = false; else subkey5[i][j]++;
48 44 rijndaelalg->shiftrow(subkey5,0,4); BYTE chavemestra[4][key_length/32]; invertechave(rijndaelalg,subkey5,chavemestra); printf("chave mestra encontrada: "); for(j = 0; j < KEY_LENGTH/32;j++) for(i = 0; i < 4; i++) printf("%x,",chavemestra[i][j]); delete rijndaelalg; delete rijndaelapi; delete userinterface; RijndaelAPI.h #ifndef _RIJNDAELAPI_H_ #define _RIJNDAELAPI_H_ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "RijndaelAlg.h" #include "UserInterface.h" /* Defines: Add any additional defines you need */ #define DIR_ENCRYPT 0 /* Are we encrpyting? */ #define DIR_DECRYPT 1 /* Are we decrpyting? */ #define MODE_ECB 1 /* Are we ciphering in ECB mode? */ #define MODE_CBC 2 /* Are we ciphering in CBC mode? */ #define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ #define TRUE 1 #define FALSE 0 #define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ /* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ #define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ #define BAD_KEY_MAT -2 /* Key material not of correct length */ #define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ #define BAD_CIPHER_MODE -4 /* Params struct passed to cipherinit invalid */ #define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ #define BAD_CIPHER_INSTANCE -7
49 45 /* CHANGE POSSIBLE: inclusion of algorithm specific defines */ #define MAX_KEY_SIZE 64 /* # of ASCII char s needed to represent a key */ #define MAX_IV_SIZE BITSPERBLOCK/8 /* # bytes needed to represent an IV */ /* Typedefs: Typedef ed data storage elements. Add any algorithm specific parameters at the bottom of the structs as appropriate. */ //typedef unsigned char BYTE; /* The structure for key information */ typedef struct BYTE direction; /* Key used for encrypting or decrypting? */ int keylen; /* Length of the key */ char keymaterial[max_key_size+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ /* The following parameters are algorithm dependent, replace or add as necessary */ int blocklen; /* block length */ word8 keysched[maxrounds+1][4][maxbc]; /* key schedule */ keyinstance; /* The structure for cipher information */ typedef struct BYTE mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ BYTE IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ /* Add any algorithm specific parameters needed here */ int blocklen; /* Sample: Handles non-128 bit block sizes (if available) */ cipherinstance; /* Function protoypes */ /* CHANGED: makekey(): parameter blocklen added this parameter is absolutely necessary if you want to setup the round keys in a variable block length setting cipherinit(): parameter blocklen added (for obvious reasons) */ class RijndaelAPI public: RijndaelAPI(RijndaelAlg* newrijndaelalg,userinterface* newuserinterface,bool newdebug); ~RijndaelAPI();
50 46 int inicializa(int direcao,int modo,char *IV,char chave[key_length/8]); int cifrabloco(byte *entrada, BYTE *saida); int decifrabloco(byte *entrada, BYTE *saida); int blockencrypt(cipherinstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer); int blockdecrypt(cipherinstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer); int cipherupdaterounds(cipherinstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer, int Rounds); private: keyinstance keyinst; cipherinstance cipherinst; RijndaelAlg* rijndaelalg; UserInterface* userinterface; bool debug; int makekey(keyinstance *key, BYTE direction,int keylen,char *keymaterial); ; int cipherinit(cipherinstance *cipher, BYTE mode, char *IV); #endif //_RIJNDAELAPI_H_ RijndaelAPI.cpp #include "RijndaelAPI.h" // RijndaelAPI::RijndaelAPI(RijndaelAlg* newrijndaelalg,userinterface* newuserinterface,bool newdebug) rijndaelalg = newrijndaelalg; userinterface = newuserinterface; debug = newdebug; // RijndaelAPI::~RijndaelAPI() // int RijndaelAPI::inicializa(int direcao,int modo,char *IV,char chave[key_length/8]) keyinst.blocklen = BLOCK_LENGTH; makekey(&keyinst, direcao, KEY_LENGTH, chave); cipherinst.blocklen = BLOCK_LENGTH; cipherinit(&cipherinst, modo, IV); return 0; //
51 47 int RijndaelAPI::cifraBloco(BYTE *entrada, BYTE *saida) cipherupdaterounds(&cipherinst,&keyinst,entrada,block_length,saida,round_number); return 0; // int RijndaelAPI::decifraBloco(BYTE *entrada, BYTE *saida) cipherupdaterounds(&cipherinst, &keyinst,entrada,block_length,saida,round_number); return 0; // int RijndaelAPI::makeKey(keyInstance *key,byte direction,int keylen,char *keymaterial) word8 k[4][maxkc]; int i, j, t; if (key == NULL) return BAD_KEY_INSTANCE; if ((direction == DIR_ENCRYPT) (direction == DIR_DECRYPT)) key->direction = direction; else return BAD_KEY_DIR; if ((keylen == 128) (keylen == 192) (keylen == 256)) key->keylen = keylen; else return BAD_KEY_MAT; if ( keymaterial ) strncpy(key->keymaterial, keymaterial, keylen/4); /* initialize key schedule: */ for(i = 0; i < key->keylen/8; i++) t = key->keymaterial[2*i]; if ((t >= 0 ) && (t <= 9 )) j = (t - 0 ) << 4; else if ((t >= a ) && (t <= f )) j = (t - a + 10) << 4; else if ((t >= A ) && (t <= F )) j = (t - A + 10) << 4; else return BAD_KEY_MAT; t = key->keymaterial[2*i+1]; if ((t >= 0 ) && (t <= 9 )) j ^= (t - 0 ); else if ((t >= a ) && (t <= f )) j ^= (t - a + 10); else if ((t >= A ) && (t <= F )) j ^= (t - A + 10); else return BAD_KEY_MAT;
52 48 k[i % 4][i / 4] = (word8) j; printf("chave usada:"); for(j = 0; j < KEY_LENGTH/32;j++) for(i = 0; i < 4; i++) printf("%x,",k[i][j]); printf("\n"); rijndaelalg->rijndaelkeysched (k, key->keylen, key->blocklen, key->keysched); return TRUE; // int RijndaelAPI::cipherInit(cipherInstance *cipher, BYTE mode, char *IV) int i, j, t; if ((mode == MODE_ECB) (mode == MODE_CBC) (mode == MODE_CFB1)) cipher->mode = mode; else return BAD_CIPHER_MODE; if (IV!= NULL) for(i = 0; i < cipher->blocklen/8; i++) t = IV[2*i]; if ((t >= 0 ) && (t <= 9 )) j = (t - 0 ) << 4; else if ((t >= a ) && (t <= f )) j = (t - a + 10) << 4; else if ((t >= A ) && (t <= F )) j = (t - A + 10) << 4; else return BAD_CIPHER_INSTANCE; t = IV[2*i+1]; if ((t >= 0 ) && (t <= 9 )) j ^= (t - 0 ); else if ((t >= a ) && (t <= f )) j ^= (t - a + 10); else if ((t >= A ) && (t <= F )) j ^= (t - A + 10); else return BAD_CIPHER_INSTANCE; cipher->iv[i] = (BYTE) j; return TRUE; // int RijndaelAPI::blockEncrypt(cipherInstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer) int i, j, t, numblocks; word8 block[4][maxbc];
53 49 /* check parameter consistency: */ if (key == NULL key->direction!= DIR_ENCRYPT (key->keylen!= 128 && key->keylen!= 192 && key->keylen!= 256)) return BAD_KEY_MAT; if (cipher == NULL (cipher->mode!= MODE_ECB && cipher->mode!= MODE_CBC && cipher->mode!= MODE_CFB1) (cipher->blocklen!= 128 && cipher->blocklen!= 192 && cipher->blocklen!= 256)) return BAD_CIPHER_STATE; numblocks = inputlen/cipher->blocklen; switch (cipher->mode) case MODE_ECB: for (i = 0; i < numblocks; i++) for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array */ block[t][j] = input[4*j+t] & 0xFF; rijndaelalg->rijndaelencrypt (block, key->keylen, cipher->blocklen, key->keysched); for (j = 0; j < cipher->blocklen/32; j++) /* parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[4*j+t] = (BYTE) block[t][j]; break; case MODE_CBC: for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse initial value into rectangular array */ block[t][j] = cipher->iv[t+4*j] & 0xFF; for (i = 0; i < numblocks; i++) for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array and exor with IV or the previous ciphertext */ block[t][j] ^= input[4*j+t] & 0xFF; rijndaelalg->rijndaelencrypt (block, key->keylen, cipher->blocklen, key->keysched); for (j = 0; j < cipher->blocklen/32; j++)
54 50 break; /* parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[4*j+t] = (BYTE) block[t][j]; default: return BAD_CIPHER_STATE; return numblocks*cipher->blocklen; // int RijndaelAPI::blockDecrypt(cipherInstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer) int i, j, t, numblocks; word8 block[4][maxbc]; if (cipher == NULL key == NULL key->direction == DIR_ENCRYPT cipher->blocklen!= key->blocklen) return BAD_CIPHER_STATE; /* check parameter consistency: */ if (key == NULL key->direction!= DIR_DECRYPT (key->keylen!= 128 && key->keylen!= 192 && key->keylen!= 256)) return BAD_KEY_MAT; if (cipher == NULL (cipher->mode!= MODE_ECB && cipher->mode!= MODE_CBC && cipher->mode!= MODE_CFB1) (cipher->blocklen!= 128 && cipher->blocklen!= 192 && cipher->blocklen!= 256)) return BAD_CIPHER_STATE; numblocks = inputlen/cipher->blocklen; switch (cipher->mode) case MODE_ECB: for (i = 0; i < numblocks; i++) for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array */ block[t][j] = input[4*j+t] & 0xFF; rijndaelalg->rijndaeldecrypt (block, key->keylen, cipher->blocklen, key->keysched);
55 51 for (j = 0; j < cipher->blocklen/32; j++) /* parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[4*j+t] = (BYTE) block[t][j]; break; case MODE_CBC: /* first block */ for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array */ block[t][j] = input[4*j+t] & 0xFF; rijndaelalg->rijndaeldecrypt (block, key->keylen, cipher->blocklen, key->keysched); for (j = 0; j < cipher->blocklen/32; j++) /* exor the IV and parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[4*j+t] = (BYTE) (block[t][j] ^ cipher->iv[t+4*j]); /* next blocks */ for (i = 1; i < numblocks; i++) for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array */ block[t][j] = input[cipher->blocklen/8+4*j+t] & 0xFF; rijndaelalg->rijndaeldecrypt (block, key->keylen, cipher->blocklen, key->keysched); for (j = 0; j < cipher->blocklen/32; j++) /* exor previous ciphertext block and parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[cipher->blocklen/8+4*j+t] = (BYTE) (block[t][j] ^ input[4*j+t-4*cipher->blocklen/32]); break; default: return BAD_CIPHER_STATE; return numblocks*cipher->blocklen; // /**
56 52 * cipherupdaterounds: * * Encrypts/Decrypts exactly one full block a specified number of rounds. * Only used in the Intermediate Value Known Answer Test. * * Returns: * TRUE - on success * BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized) */ int RijndaelAPI::cipherUpdateRounds(cipherInstance *cipher, keyinstance *key, BYTE *input, int inputlen, BYTE *outbuffer, int rounds) int j, t; word8 block[4][maxbc]; if (cipher == NULL key == NULL cipher->blocklen!= key->blocklen) return BAD_CIPHER_STATE; for (j = 0; j < cipher->blocklen/32; j++) for(t = 0; t < 4; t++) /* parse input stream into rectangular array */ block[t][j] = input[4*j+t] & 0xFF; switch (key->direction) case DIR_ENCRYPT: rijndaelalg->rijndaelencryptround(block,key->keylen,cipher->blocklen, key->keysched, rounds); break; case DIR_DECRYPT: rijndaelalg->rijndaeldecryptround(block,key->keylen,cipher->blocklen, key->keysched, rounds); break; default: return BAD_KEY_DIR; for (j = 0; j < cipher->blocklen/32; j++) /* parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++) outbuffer[4*j+t] = (BYTE) block[t][j]; return TRUE; #ifndef _RIJNDAELALG_H_ RijndaelAlg.h
57 53 #define _RIJNDAELALG_H_ #define MAXBC (256/32) #define MAXKC (256/32) #define MAXROUNDS 14 typedef unsigned char typedef unsigned short typedef unsigned long word8; word16; word32; #include <stdio.h> #include <stdlib.h> #include "conf.h" #include "UserInterface.h" #define SC ((BC - 4) >> 1) static word8 shifts[3][4][2] = 0, 0, 1, 3, 2, 2, 3, 1, ; 0, 0, 1, 5, 2, 4, 3, 3, 0, 0, 1, 7, 3, 5, 4, 4 class RijndaelAlg public: RijndaelAlg(UserInterface* newuserinterface,bool newdebug); ~RijndaelAlg(); word8 sbox(word8 byte); word8 inversesbox(word8 byte); word8 roundconstant(int index); void ShiftRow(word8 a[4][maxbc], word8 d, word8 BC); int rijndaelkeysched (word8 k[4][maxkc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc]); int rijndaelencrypt (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc]); int rijndaelencryptround (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc], int rounds);
58 54 int rijndaeldecrypt (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc]); int rijndaeldecryptround (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc], int rounds); private: UserInterface* userinterface; bool debug; word8 mul(word8 a, word8 b); void KeyAddition(word8 a[4][maxbc], word8 rk[4][maxbc], word8 BC); void Substitution(word8 a[4][maxbc], word8 box[256], word8 BC); void MixColumn(word8 a[4][maxbc], word8 BC); void InvMixColumn(word8 a[4][maxbc], word8 BC); void copiabloco(byte blocos[round_number*4+1][4][block_length/32],byte bloco[4][maxbc],int blcindex); ; #endif //_RIJNDAELALG_H_ #include "RijndaelAlg.h" #include "boxes-ref.dat" #include <stdio.h> RijndaelAlg.cpp RijndaelAlg::RijndaelAlg(UserInterface* newuserinterface,bool newdebug) userinterface = newuserinterface; debug = newdebug; // RijndaelAlg::~RijndaelAlg() // word8 RijndaelAlg::inverseSBox(word8 byte) return Si[byte]; // word8 RijndaelAlg::sBox(word8 byte) return S[byte]; // word8 RijndaelAlg::roundConstant(int index) return rcon[index]; // word8 RijndaelAlg::mul(word8 a, word8 b) /* multiply two elements of GF(2^m)
59 55 * needed for MixColumn and InvMixColumn */ if (a && b) return Alogtable[(Logtable[a] + Logtable[b])%255]; else return 0; // void RijndaelAlg::KeyAddition(word8 a[4][maxbc],word8 rk[4][maxbc],word8 BC) /* Exor corresponding text input and round key input bytes */ int i, j; for(i = 0; i < 4; i++) for(j = 0; j < BC; j++) a[i][j] ^= rk[i][j]; // void RijndaelAlg::ShiftRow(word8 a[4][maxbc], word8 d, word8 BC) /* Row 0 remains unchanged * The other three rows are shifted a variable amount */ word8 tmp[maxbc]; int i, j; for(i = 1; i < 4; i++) for(j = 0; j < BC; j++) tmp[j] = a[i][(j + shifts[sc][i][d]) % BC]; for(j = 0; j < BC; j++) a[i][j] = tmp[j]; // void RijndaelAlg::Substitution(word8 a[4][maxbc], word8 box[256], word8 BC) /* Replace every byte of the input by the byte at that place * in the nonlinear S-box */ int i, j; for(i = 0; i < 4; i++) for(j = 0; j < BC; j++) a[i][j] = box[a[i][j]] ; // void RijndaelAlg::MixColumn(word8 a[4][maxbc], word8 BC) /* Mix the four bytes of every column in a linear way */ word8 b[4][maxbc]; int i, j; for(j = 0; j < BC; j++) for(i = 0; i < 4; i++) b[i][j] = mul(2,a[i][j]) ^ mul(3,a[(i + 1) % 4][j]) ^ a[(i + 2) % 4][j] ^ a[(i + 3) % 4][j]; for(i = 0; i < 4; i++)
60 56 for(j = 0; j < BC; j++) a[i][j] = b[i][j]; // void RijndaelAlg::InvMixColumn(word8 a[4][maxbc], word8 BC) /* Mix the four bytes of every column in a linear way * This is the opposite operation of Mixcolumn */ word8 b[4][maxbc]; int i, j; for(j = 0; j < BC; j++) for(i = 0; i < 4; i++) b[i][j] = mul(0xe,a[i][j]) ^ mul(0xb,a[(i + 1) % 4][j]) ^ mul(0xd,a[(i + 2) % 4][j]) ^ mul(0x9,a[(i + 3) % 4][j]); for(i = 0; i < 4; i++) for(j = 0; j < BC; j++) a[i][j] = b[i][j]; // int RijndaelAlg::rijndaelKeySched (word8 k[4][maxkc], int keybits, int blockbits, word8 W[MAXROUNDS+1][4][MAXBC]) /* Calculate the necessary round keys * The number of calculations depends on keybits and blockbits */ int KC, BC, ROUNDS; int i, j, t, rconpointer = 0; word8 tk[4][maxkc]; switch (keybits) case 128: KC = 4; break; case 192: KC = 6; break; case 256: KC = 8; break; default : return (-1); switch (blockbits) case 128: BC = 4; break; case 192: BC = 6; break; case 256: BC = 8; break; default : return (-2); switch (keybits >= blockbits? keybits : blockbits) case 128: ROUNDS = 10; break; case 192: ROUNDS = 12; break; case 256: ROUNDS = 14; break; default : return (-3); /* this cannot happen */
61 57 for(j = 0; j < KC; j++) for(i = 0; i < 4; i++) tk[i][j] = k[i][j]; t = 0; /* copy values into round key array */ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j]; /* while not enough round key material calculated */ while (t < (ROUNDS+1)*BC) /* calculate new values */ for(i = 0; i < 4; i++) tk[i][0] ^= S[tk[(i+1)%4][KC-1]]; tk[0][0] ^= rcon[rconpointer++]; if (KC!= 8) for(j = 1; j < KC; j++) for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; else for(j = 1; j < KC/2; j++) for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; for(i = 0; i < 4; i++) tk[i][kc/2] ^= S[tk[i][KC/2-1]]; for(j = KC/2 + 1; j < KC; j++) for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; /* copy values into round key array */ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j]; return 0; // int RijndaelAlg::rijndaelEncrypt (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc]) /* Encryption of one block. */ int r, BC, ROUNDS; switch (blockbits) case 128: BC = 4; break; case 192: BC = 6; break; case 256: BC = 8; break; default : return (-2); switch (keybits >= blockbits? keybits : blockbits) case 128: ROUNDS = 10; break; case 192: ROUNDS = 12; break;
62 58 case 256: ROUNDS = 14; break; default : return (-3); /* this cannot happen */ /* begin with a key addition */ KeyAddition(a,rk[0],BC); /* ROUNDS-1 ordinary rounds */ for(r = 1; r < ROUNDS; r++) Substitution(a,S,BC); ShiftRow(a,0,BC); MixColumn(a,BC); KeyAddition(a,rk[r],BC); /* Last round is special: there is no MixColumn */ Substitution(a,S,BC); ShiftRow(a,0,BC); KeyAddition(a,rk[ROUNDS],BC); return 0; // void RijndaelAlg::copiaBloco(BYTE blocos[round_number*4+1][4][block_length/32],byte bloco[4][maxbc],int blcindex) unsigned int i,j; for(i = 0; i < 4; i++) for(j =0; j <BLOCK_LENGTH/32;j++)blocos[blcIndex][i][j] = bloco[i][j]; // int RijndaelAlg::rijndaelEncryptRound (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc], int rounds) /* Encrypt only a certain number of rounds. * Only used in the Intermediate Value Known Answer Test. */ int r, BC, ROUNDS; switch (blockbits) case 128: BC = 4; break; case 192: BC = 6; break; case 256: BC = 8; break; default : return (-2); switch (keybits >= blockbits? keybits : blockbits) case 128: ROUNDS = 10; break;
63 59 case 192: ROUNDS = 12; break; case 256: ROUNDS = 14; break; default : return (-3); /* this cannot happen */ /* make number of rounds sane */ if (rounds > ROUNDS) rounds = ROUNDS; BYTE blocos[round_number*4+1][4][block_length/32]; int blcindex =0; /* begin with a key addition */ if(debug)copiabloco(blocos,a,blcindex++); KeyAddition(a,rk[0],BC); if(debug)copiabloco(blocos,a,blcindex++); /* at most ROUNDS-1 ordinary rounds */ //for(r = 1; (r <= rounds) && (r < ROUNDS); r++) for(r = 1;r < rounds; r++) Substitution(a,S,BC); if(debug)copiabloco(blocos,a,blcindex++); ShiftRow(a,0,BC); if(debug)copiabloco(blocos,a,blcindex++); MixColumn(a,BC); if(debug)copiabloco(blocos,a,blcindex++); KeyAddition(a,rk[r],BC); if(debug)copiabloco(blocos,a,blcindex++); /* if necessary, do the last, special, round: */ //if (rounds == ROUNDS) Substitution(a,S,BC); if(debug)copiabloco(blocos,a,blcindex++); ShiftRow(a,0,BC); if(debug)copiabloco(blocos,a,blcindex++); KeyAddition(a,rk[rounds],BC); if(debug)copiabloco(blocos,a,blcindex++); // if(debug)userinterface->mostrablocoscifrando(blocos);
64 60 return 0; // int RijndaelAlg::rijndaelDecrypt (word8 a[4][maxbc], int keybits,int blockbits, word8 rk[maxrounds+1][4][maxbc]) int r, BC, ROUNDS; switch (blockbits) case 128: BC = 4; break; case 192: BC = 6; break; case 256: BC = 8; break; default : return (-2); switch (keybits >= blockbits? keybits : blockbits) case 128: ROUNDS = 10; break; case 192: ROUNDS = 12; break; case 256: ROUNDS = 14; break; default : return (-3); /* this cannot happen */ /* To decrypt: apply the inverse operations of the encrypt routine, * in opposite order * * (KeyAddition is an involution: it s equal to its inverse) * (the inverse of Substitution with table S is Substitution with * the inverse table of S) * (the inverse of Shiftrow is Shiftrow over a suitable distance) */ /* First the special round: * without InvMixColumn * with extra KeyAddition */ KeyAddition(a,rk[ROUNDS],BC); Substitution(a,Si,BC); ShiftRow(a,1,BC); /* ROUNDS-1 ordinary rounds */ for(r = ROUNDS-1; r > 0; r--) KeyAddition(a,rk[r],BC); InvMixColumn(a,BC); Substitution(a,Si,BC); ShiftRow(a,1,BC); /* End with the extra key addition */
65 61 KeyAddition(a,rk[0],BC); return 0; // int RijndaelAlg::rijndaelDecryptRound (word8 a[4][maxbc], int keybits, int blockbits, word8 rk[maxrounds+1][4][maxbc], int rounds) /* Decrypt only a certain number of rounds. * Only used in the Intermediate Value Known Answer Test. * Operations rearranged such that the intermediate values * of decryption correspond with the intermediate values * of encryption. */ int r, BC, ROUNDS; switch (blockbits) case 128: BC = 4; break; case 192: BC = 6; break; case 256: BC = 8; break; default : return (-2); switch (keybits >= blockbits? keybits : blockbits) case 128: ROUNDS = 10; break; case 192: ROUNDS = 12; break; case 256: ROUNDS = 14; break; default : return (-3); /* this cannot happen */ /* make number of rounds sane */ if (rounds > ROUNDS) rounds = ROUNDS; /* First the special round: * without InvMixColumn * with extra KeyAddition */ //erro: KeyAddition(a,rk[ROUNDS],BC); KeyAddition(a,rk[rounds],BC); Substitution(a,Si,BC); ShiftRow(a,1,BC); /* ROUNDS-1 ordinary rounds */ //Erro: for(r = ROUNDS-1; r > rounds; r--) for(r = rounds-1; r > 0; r--) KeyAddition(a,rk[r],BC); InvMixColumn(a,BC); Substitution(a,Si,BC); ShiftRow(a,1,BC);
66 62 /*ERRO:if (rounds == 0) // End with the extra key addition KeyAddition(a,rk[0],BC); */ KeyAddition(a,rk[0],BC); return 0; 1Order5RoundsBeginExt.cpp #include "Utils.h" #include <cstdio> #define NUMBER_OF_INTEGRAL_BLOCKS 5 void get_integral_blocks(uint16 plaintext_blocks[][maxbc],uint16 blocks_indexes[][16]) unsigned int i,j; uint16 valores_dos_constantes[number_of_integral_blocks]; unsigned int indexes[number_of_integral_blocks]; for(i = 0;i < NUMBER_OF_INTEGRAL_BLOCKS;i++) valores_dos_constantes[i] = i; indexes[i] = 0; uint16 t; for(i = 0;i < 65536;i++) t = (plaintext_blocks[i][0] & 0x0FFF); for(j = 0;j < NUMBER_OF_INTEGRAL_BLOCKS;j++) if(t == valores_dos_constantes[j]) blocks_indexes[j][indexes[j]++] = i; break; void square_attack_1_order_5_rounds_begin_extension() uint32 i,j,k,t,x; //loop index Utils* utils = new Utils(); MiniRijndaelAlg* minirijndaelalg = new MiniRijndaelAlg(); MiniRijndaelAPI* minirijndaelapi = new MiniRijndaelAPI(miniRijndaelAlg); uint16 plaintext_blocks[65536][maxbc]; uint16 ciphertext_blocks[65536][maxbc];
67 63 uint16 temp_blocks[65536][maxbc]; uint16 selected_blocks[number_of_integral_blocks][16][maxbc]; uint16 blocks_indexes[number_of_integral_blocks][16]; utils->geraconjuntointegral_4_order(plaintext_blocks,0); uint16 kkey[maxkc] = 0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0; FILE* random_source_file = fopen("/dev/urandom","r"); fread(kkey,sizeof(uint16),kc,random_source_file); if(random_source_file == NULL) printf("error openning file\n"); kkey[0] = 0xA; kkey[1] = 0xB; kkey[2] = 0xC; kkey[3] = 0xD; printf("chave:"); for(i = 0;i < KC;i++)printf("%X,",kkey[i]); printf("\n"); minirijndaelapi->init(0,kkey); for(i = 0;i < 65536;i++) minirijndaelapi->encrypt(plaintext_blocks[i],ciphertext_blocks[i]); uint16 subkey0[4] = 0x0,0x0,0x0,0x0; uint16 subkey0_c = 0; uint16 subkey4bits; uint16 subkey6[4] = 0x0,0x0,0x0,0x0; uint16 balance[number_of_integral_blocks]; uint16 balances; uint16 P4[NUMBER_OF_INTEGRAL_BLOCKS][16][4]; uint16 block4bits[number_of_integral_blocks]; while(true) inicio: printf("trying subkey: "); for(i = 0;i < KC;i++)printf("%X,",subkey0[i]); printf("\n"); for(i = 0;i < 65536;i++) for(j = 0;j < 4;j++) temp_blocks[i][j] = plaintext_blocks[i][j];
68 64 for(i = 0;i < 65536;i++) minirijndaelalg->keyaddition(temp_blocks[i],subkey0); minirijndaelalg->substitution(temp_blocks[i]); minirijndaelalg->shiftrow(temp_blocks[i],0); minirijndaelalg->mixcolumn(temp_blocks[i]); get_integral_blocks(temp_blocks,blocks_indexes); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) for(j = 0;j < 4;j++) selected_blocks[x][i][j] = ciphertext_blocks[blocks_indexes[x][i]][j]; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) minirijndaelalg->shiftrow(selected_blocks[x][i],1); j = 0; subkey6[0] = 0; subkey6[1] = 0; subkey6[2] = 0; subkey6[3] = 0; while(j < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) P4[x][t][j] = minirijndaelalg->invsubstitution(selected_blocks[x][t][j] ^ subkey6[j]); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) minirijndaelalg->invmixcolumn(p4[x][t]); minirijndaelalg->shiftrow(p4[x][t],1); subkey4bits = 0; i = 0; k = j; while(i < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balance[x] = 0;
69 65 for(t = 0;t < 16;t++) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) block4bits[x] = P4[x][t][k] >> (12 - (i*4)); balance[x] ^= minirijndaelalg->invsubstitution(low4(subkey4bits) ^ low4(block4bits[x])); balances = 0; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balances += balance[x]; if(balances == 0) i++; subkey4bits = 0; k = ((k + 1)%4); if(i == 4) printf("achou 16bits\n"); j++; if(j == 4)goto achou; else subkey4bits++; if(subkey4bits == 0x10) i = 4; if(subkey6[j] == 0xFFFF) //trocar subkey0 if(subkey0_c == 0xFFFF) printf("o limite das chaves foi atingido e a chave n~ao foi encontrada\n"); goto fim; subkey0_c++; subkey0[0] = (subkey0_c & 0xF000); subkey0[1] = (subkey0_c & 0x0F00); subkey0[2] = (subkey0_c & 0x00F0); subkey0[3] = (subkey0_c & 0x000F); goto inicio; subkey6[j]++; achou: minirijndaelalg->shiftrow(subkey6,0); printf("subchave encontrada: "); for(i = 0;i < KC;i++)printf("%X,",subKey6[i]);
70 66 printf("\n"); uint16 chavemestra[kc]; utils->invertechave(minirijndaelalg,subkey6,chavemestra); printf("chave mestra encontrada: "); for(j = 0; j < KC;j++) printf("%x,",chavemestra[j]); printf("\n"); fim:delete utils; delete minirijndaelapi; delete minirijndaelalg; printf("fim\n"); 1Order5RoundsEndExt.cpp #include "Utils.h" #define NUMBER_OF_INTEGRAL_BLOCKS 5 void square_attack_1_order_5_rounds_end_extension() unsigned int i,j,t,k,x; //loop index Utils* utils = new Utils(); MiniRijndaelAlg* minirijndaelalg = new MiniRijndaelAlg(); MiniRijndaelAPI* minirijndaelapi = new MiniRijndaelAPI(miniRijndaelAlg); uint16 plaintext_blocks[number_of_integral_blocks][16][maxbc]; uint16 ciphertext_blocks[number_of_integral_blocks][16][maxbc]; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) utils->geraconjuntointegral_1_order(plaintext_blocks[x],x); uint16 kkey[maxkc] = 0x0,0x1,0x2,0x3,0x0,0x1,0x2,0x3; minirijndaelapi->init(0,kkey); printf(" \n"); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) minirijndaelapi->encrypt(plaintext_blocks[x][i],ciphertext_blocks[x][i]); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) minirijndaelalg->shiftrow(ciphertext_blocks[x][i],1);
71 67 uint16 subkey4bits; uint16 subkey6[4] = 0x0,0x0,0x0,0x0; uint16 balance[number_of_integral_blocks]; uint16 balances; uint16 P4[NUMBER_OF_INTEGRAL_BLOCKS][16][4]; uint16 block4bits[number_of_integral_blocks]; j = 0; while(j < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) P4[x][t][j] = minirijndaelalg->invsubstitution(ciphertext_blocks[x][t][j] ^ subkey6[j]); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) minirijndaelalg->invmixcolumn(p4[x][t]); minirijndaelalg->shiftrow(p4[x][t],1); subkey4bits = 0; i = 0; k = j; while(i < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balance[x] = 0; for(t = 0;t < 16;t++) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) block4bits[x] = P4[x][t][k] >> (12 - (i*4)); balance[x] ^= minirijndaelalg->invsubstitution(low4(subkey4bits) ^ low4(block4bits[x])); balances = 0; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balances += balance[x]; if(balances == 0) i++; subkey4bits = 0; k = ((k + 1)%4); if(i == 4) printf("achou 16bits\n"); j++;
72 68 else subkey4bits++; if(subkey4bits == 0x10) i = 4; if(subkey6[j] == 0xFFFF) printf("valor de chave estrapolou limites\n"); goto fim; subkey6[j]++; minirijndaelalg->shiftrow(subkey6,0); printf("subchave encontrada: "); for(i = 0;i < KC;i++)printf("%X,",subKey6[i]); printf("\n"); uint16 chavemestra[kc]; utils->invertechave(minirijndaelalg,subkey6,chavemestra); printf("chave mestra encontrada: "); for(j = 0; j < KC;j++) printf("%x,",chavemestra[j]); printf("\n"); fim:delete utils; delete minirijndaelapi; delete minirijndaelalg; printf("fim\n"); 1Order6Rounds.cpp #include "Utils.h" #include <cstdio> #define NUMBER_OF_INTEGRAL_BLOCKS 5 void get_integral_blocks(uint16 plaintext_blocks[][maxbc],uint16 blocks_indexes[][16]) unsigned int i,j; uint16 valores_dos_constantes[number_of_integral_blocks]; unsigned int indexes[number_of_integral_blocks]; for(i = 0;i < NUMBER_OF_INTEGRAL_BLOCKS;i++) valores_dos_constantes[i] = i; indexes[i] = 0;
73 69 uint16 t; for(i = 0;i < 65536;i++) t = (plaintext_blocks[i][0] & 0x0FFF); for(j = 0;j < NUMBER_OF_INTEGRAL_BLOCKS;j++) if(t == valores_dos_constantes[j]) blocks_indexes[j][indexes[j]++] = i; break; void square_attack_1_order_6_rounds() uint32 i,j,k,t,x; //loop index Utils* utils = new Utils(); MiniRijndaelAlg* minirijndaelalg = new MiniRijndaelAlg(); MiniRijndaelAPI* minirijndaelapi = new MiniRijndaelAPI(miniRijndaelAlg); uint16 plaintext_blocks[65536][maxbc]; uint16 ciphertext_blocks[65536][maxbc]; uint16 temp_blocks[65536][maxbc]; uint16 selected_blocks[number_of_integral_blocks][16][maxbc]; uint16 blocks_indexes[number_of_integral_blocks][16]; utils->geraconjuntointegral_4_order(plaintext_blocks,0); uint16 kkey[maxkc] = 0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0; FILE* random_source_file = fopen("/dev/urandom","r"); fread(kkey,sizeof(uint16),kc,random_source_file); if(random_source_file == NULL) printf("error openning file\n"); kkey[0] = 0xA; kkey[1] = 0xB; kkey[2] = 0xC; kkey[3] = 0xD; printf("chave:"); for(i = 0;i < KC;i++)printf("%X,",kkey[i]); printf("\n"); minirijndaelapi->init(0,kkey); for(i = 0;i < 65536;i++) minirijndaelapi->encrypt(plaintext_blocks[i],ciphertext_blocks[i]);
74 70 uint16 subkey0[4] = 0x0,0x0,0x0,0x0; uint16 subkey0_c = 0; uint16 subkey4bits; uint16 subkey6[4] = 0x0,0x0,0x0,0x0; uint16 balance[number_of_integral_blocks]; uint16 balances; uint16 P4[NUMBER_OF_INTEGRAL_BLOCKS][16][4]; uint16 block4bits[number_of_integral_blocks]; while(true) inicio: printf("trying subkey: "); for(i = 0;i < KC;i++)printf("%X,",subkey0[i]); printf("\n"); for(i = 0;i < 65536;i++) for(j = 0;j < 4;j++) temp_blocks[i][j] = plaintext_blocks[i][j]; for(i = 0;i < 65536;i++) minirijndaelalg->keyaddition(temp_blocks[i],subkey0); minirijndaelalg->substitution(temp_blocks[i]); minirijndaelalg->shiftrow(temp_blocks[i],0); minirijndaelalg->mixcolumn(temp_blocks[i]); get_integral_blocks(temp_blocks,blocks_indexes); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) for(j = 0;j < 4;j++) selected_blocks[x][i][j] = ciphertext_blocks[blocks_indexes[x][i]][j]; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(i = 0;i < 16;i++) minirijndaelalg->shiftrow(selected_blocks[x][i],1); j = 0; subkey6[0] = 0; subkey6[1] = 0; subkey6[2] = 0;
75 71 subkey6[3] = 0; while(j < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) P4[x][t][j] = minirijndaelalg->invsubstitution(selected_blocks[x][t][j] ^ subkey6[j]); for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) for(t = 0;t < 16;t++) minirijndaelalg->invmixcolumn(p4[x][t]); minirijndaelalg->shiftrow(p4[x][t],1); subkey4bits = 0; i = 0; k = j; while(i < 4) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balance[x] = 0; for(t = 0;t < 16;t++) for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) block4bits[x] = P4[x][t][k] >> (12 - (i*4)); balance[x] ^= minirijndaelalg->invsubstitution(low4(subkey4bits) ^ low4(block4bits[x])); balances = 0; for(x = 0;x < NUMBER_OF_INTEGRAL_BLOCKS;x++) balances += balance[x]; if(balances == 0) i++; subkey4bits = 0; k = ((k + 1)%4); if(i == 4) printf("achou 16bits\n"); j++; if(j == 4)goto achou; else subkey4bits++; if(subkey4bits == 0x10) i = 4; if(subkey6[j] == 0xFFFF) //trocar subkey0 if(subkey0_c == 0xFFFF)
76 72 printf("o limite das chaves foi atingido e a chave n~ao foi encontrada\n"); goto fim; subkey0_c++; subkey0[0] = (subkey0_c & 0xF000); subkey0[1] = (subkey0_c & 0x0F00); subkey0[2] = (subkey0_c & 0x00F0); subkey0[3] = (subkey0_c & 0x000F); goto inicio; subkey6[j]++; achou: minirijndaelalg->shiftrow(subkey6,0); printf("subchave encontrada: "); for(i = 0;i < KC;i++)printf("%X,",subKey6[i]); printf("\n"); uint16 chavemestra[kc]; utils->invertechave(minirijndaelalg,subkey6,chavemestra); printf("chave mestra encontrada: "); for(j = 0; j < KC;j++) printf("%x,",chavemestra[j]); printf("\n"); fim:delete utils; delete minirijndaelapi; delete minirijndaelalg; printf("fim\n"); #include "Utils.h" 4Order5Rounds.cpp void square_attack_4_order_5_rounds() uint32 i,j,t; //loop index Utils* utils = new Utils(); MiniRijndaelAlg* minirijndaelalg = new MiniRijndaelAlg(); MiniRijndaelAPI* minirijndaelapi = new MiniRijndaelAPI(miniRijndaelAlg);
77 73 uint16 plaintext_blocks1[65536][maxbc]; uint16 ciphertext_blocks1[65536][maxbc]; uint16 plaintext_blocks2[65536][maxbc]; uint16 ciphertext_blocks2[65536][maxbc]; utils->geraconjuntointegral_4_order(plaintext_blocks1,0); utils->geraconjuntointegral_4_order(plaintext_blocks2,1); uint16 kkey[maxkc] = 0x1,0x2,0x3,0x4,0x0,0x1,0x2,0x3; printf("chave:"); for(i = 0;i < KC;i++)printf("%X,",kkey[i]); printf("\n"); minirijndaelapi->init(0,kkey); for(i = 0;i < 65536;i++) minirijndaelapi->encrypt(plaintext_blocks1[i],ciphertext_blocks1[i]); minirijndaelapi->encrypt(plaintext_blocks2[i],ciphertext_blocks2[i]); for (i = 0; i < 65536; i++) minirijndaelalg->shiftrow(ciphertext_blocks1[i],1); minirijndaelalg->shiftrow(ciphertext_blocks2[i],1); uint16 subkey6[4] = 0x0,0x0,0x0,0x0; uint16 balance1,balance2; bool naoachouchave; for (i = 0; i < 4; i++) subkey6[i] = 0; naoachouchave = true; while(naoachouchave) balance1 = 0; balance2 = 0; for(t = 0;t < 65536;t++) balance1 ^= minirijndaelalg->invsubstitution(ciphertext_blocks1[t][i] ^ subkey6[i]); balance2 ^= minirijndaelalg->invsubstitution(ciphertext_blocks2[t][i] ^ subkey6[i]); if((balance1 == 0x0)&&(balance2 == 0x0)) printf("achou: %X\n",subKey6[i]); naoachouchave = false; else subkey6[i]++; //transformar subchave de bytes para subchave de nibbles
78 74 minirijndaelalg->shiftrow(subkey6,0); printf("subchave encontrada: "); for(i = 0;i < KC;i++)printf("%X,",subKey6[i]); printf("\n"); uint16 chavemestra[kc]; utils->invertechave(minirijndaelalg,subkey6,chavemestra); printf("chave mestra encontrada: "); for(j = 0; j < KC;j++) printf("%x,",chavemestra[j]); printf("\n"); delete utils; delete minirijndaelapi; delete minirijndaelalg; #ifndef _MINIRIJNDAELAPI_H_ #define _MINIRIJNDAELAPI_H_ #include <cstdio> #include "MiniRijndaelAlg.h" MiniRijndaelAPI.h #define DIR_ENCRYPT 0 /* Are we encrpyting? */ #define DIR_DECRYPT 1 /* Are we decrpyting? */ #define MODE_ECB 1 /* Are we ciphering in ECB mode? */ #define MODE_CBC 2 /* Are we ciphering in CBC mode? */ #define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ #define TRUE 1 #define FALSE 0 #define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ /* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ #define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ #define BAD_KEY_MAT -2 /* Key material not of correct length */ #define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ #define BAD_CIPHER_MODE -4 /* Params struct passed to cipherinit invalid */ #define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ #define BAD_CIPHER_INSTANCE -7 /* CHANGE POSSIBLE: inclusion of algorithm specific defines */ #define MAX_KEY_SIZE 64 /* # of ASCII char s needed to
79 75 represent a key */ #define MAX_IV_SIZE BITSPERBLOCK/8 /* # bytes needed to represent an IV */ /* The structure for key information */ typedef struct unsigned char direction; /* Key used for encrypting or decrypting? */ int keylen; /* Length of the key */ char keymaterial[max_key_size+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ /* The following parameters are algorithm dependent, replace or add as necessary */ int blocklen; /* block length */ unsigned short int keysched[maxrounds+1][maxbc]; /* key schedule */ keyinstance; /* The structure for cipher information */ typedef struct unsigned char mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ unsigned char IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ /* Add any algorithm specific parameters needed here */ int blocklen; /*Sample: Handles non-128 bit block sizes (if available)*/ cipherinstance; class MiniRijndaelAPI public: MiniRijndaelAPI(MiniRijndaelAlg* minirijndaelalg); ~MiniRijndaelAPI(); int init(unsigned char direction,uint16 kkey[maxkc]); int encrypt(uint16 plain_text[maxbc], uint16 cipher_text[maxbc]); int decrypt(uint16 plain_text[maxbc], uint16 cipher_text[maxbc]); int encrypt(uint16 a[maxbc], uint16 b[maxbc], uint16 rk[maxrounds+1][maxbc]); int decrypt (uint16 a[maxbc], uint16 b[maxbc], uint16 rk[maxrounds+1][maxbc]); void printbalance(); protected: keyinstance key; MiniRijndaelAlg* minirijndaelalg; uint16 balance[4]; ; #endif //_MINIRIJNDAELAPI_H_ #include "MiniRijndaelAPI.h" MiniRijndaelAPI.cpp
80 76 MiniRijndaelAPI::MiniRijndaelAPI(MiniRijndaelAlg* minirijndaelalg) this->minirijndaelalg = minirijndaelalg; balance[0] = 0; balance[1] = 0; balance[2] = 0; balance[3] = 0; // MiniRijndaelAPI::~MiniRijndaelAPI() // int MiniRijndaelAPI::init(unsigned char direction,uint16 kkey[maxkc]) key.direction = direction; key.keylen = 16*KC; key.blocklen = 16*BC; this->minirijndaelalg->rijndaelkeysched(kkey, key.keysched); printf("subchaves usadas:\n "); for(int j =0;j < ROUNDS+1;j++) for(int i = 0;i < KC;i++)printf("%X,",key.keySched[j][i]); printf("\n"); // int MiniRijndaelAPI::encrypt(uint16 a[maxbc], uint16 b[maxbc], uint16 rk[maxrounds+1][maxbc]) int r, j; for (j = 0; j < BC; j ++) b[j] = a[j]; this->minirijndaelalg->keyaddition(b,rk[0]); this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[1]); this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[2]); this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[3]);
81 77 this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[4]); this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[5]); if (ROUNDS >= 7) this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[6]); if (ROUNDS >= 8) this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->mixcolumn(b); this->minirijndaelalg->keyaddition(b,rk[7]); // Last round: there is no MixColumn this->minirijndaelalg->substitution(b); this->minirijndaelalg->shiftrow(b,0); this->minirijndaelalg->keyaddition(b,rk[rounds]); return 0; // int MiniRijndaelAPI::decrypt (uint16 a[maxbc], uint16 b[maxbc], uint16 rk[maxrounds+1][maxbc]) int j; for (j = 0; j < BC; j ++) b[j] = a[j]; this->minirijndaelalg->keyaddition(b,rk[rounds]); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); if (ROUNDS >= 8) this->minirijndaelalg->keyaddition(b,rk[7]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1);
82 78 if (ROUNDS >= 7) this->minirijndaelalg->keyaddition(b,rk[6]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[5]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[4]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[3]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[2]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[1]); this->minirijndaelalg->invmixcolumn(b); this->minirijndaelalg->invsubstitution(b); this->minirijndaelalg->shiftrow(b,1); this->minirijndaelalg->keyaddition(b,rk[0]); return 0; // int MiniRijndaelAPI::encrypt(uint16 plain_text[maxbc], uint16 cipher_text[maxbc]) unsigned int i; //loop index for (i = 0; i < BC; i ++) cipher_text[i] = plain_text[i]; i = 0; this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i++]); while(i < ROUNDS) this->minirijndaelalg->substitution(cipher_text); this->minirijndaelalg->shiftrow(cipher_text,0); this->minirijndaelalg->mixcolumn(cipher_text);
83 79 this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i++]); this->minirijndaelalg->substitution(cipher_text); this->minirijndaelalg->shiftrow(cipher_text,0); this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i]); // void MiniRijndaelAPI::printBalance() printf("balance: "); for(int i = 0;i < 4;i++)printf("%X,",balance[i]); printf("\n"); // int MiniRijndaelAPI::decrypt(uint16 plain_text[maxbc], uint16 cipher_text[maxbc]) unsigned int i; //loop index for (i = 0; i < BC; i ++) cipher_text[i] = plain_text[i]; i = ROUNDS; this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i--]); this->minirijndaelalg->invsubstitution(cipher_text); this->minirijndaelalg->shiftrow(cipher_text,1); while(i > 0) this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i--]); this->minirijndaelalg->invmixcolumn(cipher_text); this->minirijndaelalg->invsubstitution(cipher_text); this->minirijndaelalg->shiftrow(cipher_text,1); this->minirijndaelalg->keyaddition(cipher_text,key.keysched[i]); // #ifndef _MINIRIJNDAELALG_H_ #define _MINIRIJNDAELALG_H_ #include <cstdio> #include <cstdlib> #include <gmp.h> #include <cstring> MiniRijndaelAlg.h /************** PARAMETERS: ************************************************/ #define NP // 65536=16^4 =full // 256=4^4 =test for time evaluation // 16=2^4 =test for time evaluation #define KC 4 // # of 16 bit columns
84 80 #define BC 4 // # of 16 bit columns #define ROUNDS 6 // # of rounds = 6, 7 or 8 #define ORDER 4 // order of the attack: 4, 8 or 12 #define ORDER8 1 //#define ORDER12 1 // ORDER12 requires ORDER8 /*****************************************************************************/ #define MAXKC 8 // 128/16 : Key Columns #define MAXBC 8 // 128/16 : Block Columns #define MAXROUNDS 14 #define MAXSTEPS 32 // max nr of steps #define ARRAY_SIZE 8 // array size for gmp array initialization #define ROOT 0x13 // primitive polynomial x^4+x+1 // could also be 0x19 : x^4+x^3+1 //#define WRTSTEPS 1 // write partial result to file in disk #define PTSTEPS 1 // complete results to screen and file #define VSUM 1 // include GMP-SUMs? //#define PT 1 // print plain texts (to screen)? //#define CT 1 // print cipher texts (to screen)? //#define CHKENC 1 // check consistency of encryption? typedef unsigned long long int typedef unsigned long int typedef unsigned short int typedef unsigned char typedef signed long int typedef signed short int typedef signed char uint64; uint32; uint16; uint8; int32; int16; int8; #define SC (BC - 4) #define low4(x) ((x)&0xf) #define low8(x) ((x)&0xff) #define low12(x) ((x)&0xfff) #define low16(x) ((x)&0xffff) #define low32(x) ((x)&0xffffffff) #define low48(x) ((x)&0xffffffffffff) //****************************************************************** // GLOBAL MATRIX FOR SHIFTROW: //****************************************************************** static uint8 shifts[5][4][2] = //1st column: encryption; 2nd column: decryption 0, 0, 1, 3, 2, 2, 3, 1, 0, 0,
85 81 1, 4, 2, 3, 3, 2, 0, 0, 1, 5, 2, 4, 3, 3, 0, 0, 1, 6, 2, 5, 4, 3, ; 0, 0, 1, 7, 3, 5, 4, 4 //****************************************************************** // GLOBAL ACCUMULATORS FOR DETERMINATION OF ACTIVE NIBBLES: //****************************************************************** class MiniRijndaelAlg public: MiniRijndaelAlg(); ~MiniRijndaelAlg(); ; void KeyAddition(uint16 a[maxbc], uint16 rk[maxbc]); void ShiftRow(uint16 a[maxbc],int d); void Substitution(uint16 a[maxbc]); uint16 Substitution(uint16 a); uint16 InvSubstitution(uint16 a); void InvSubstitution(uint16 a[maxbc]); void MixColumn(uint16 a[maxbc]); void InvMixColumn(uint16 a[maxbc]); uint16 InvMixColumn(uint16 a); int rijndaelkeysched(uint16 k[maxkc],uint16 W[MAXROUNDS+1][MAXBC]); uint16 roundconstant(int index); #endif //_MINIRIJNDAELALG_H_ #include "MiniRijndaelAlg.h" #include "smat.h" #include "simat.h" MiniRijndaelAlg.cpp
86 82 #include "mcmat.h" #include "imcmat.h" #include "Mini-boxes-ref.dat" MiniRijndaelAlg::MiniRijndaelAlg() // MiniRijndaelAlg::~MiniRijndaelAlg() // // * xor corresponding text input and round key input bytes // * BC is the number of Block Columns void MiniRijndaelAlg::KeyAddition(uint16 a[maxbc], uint16 rk[maxbc]) int j; for(j = 0; j < BC; j++) a[j] ^= rk[j]; /* KeyAddition */ // // * Row 0 remains unchanged // - The other three rows are shifted a variable amount // * d stands for the direction of operation: 0: encrypt; 1: decrypt */ void MiniRijndaelAlg::ShiftRow(uint16 a[maxbc], int d) uint16 b[maxbc]; int j; for(j = 0; j < BC; j++) b[j] = a[j]; for(j = 0; j < BC; j++) // 1st row not shifted a[j] ^= (low4(b[j]>>8)<<8) ^ (low4(b[(j+shifts[sc][1][d]) % BC]>>8)<<8); a[j] ^= (low4(b[j]>>4)<<4) ^ (low4(b[(j+shifts[sc][2][d]) % BC]>>4)<<4); a[j] ^= low4(b[j]) ^ low4(b[(j+shifts[sc][3][d]) % BC]) ; /* ShiftRow */ // void MiniRijndaelAlg::Substitution(uint16 a[maxbc]) int j; for(j = 0; j < BC; j++) a[j] = S4[a[j]]; /* Substitution */ // uint16 MiniRijndaelAlg::Substitution(uint16 a)
87 83 return S4[a]; /* Substitution */ // uint16 MiniRijndaelAlg::InvSubstitution(uint16 a) return S4i[a]; // void MiniRijndaelAlg::InvSubstitution(uint16 a[maxbc]) int j; for(j = 0; j < BC; j++) a[j] = S4i[a[j]]; /* Substitution */ // void MiniRijndaelAlg::MixColumn(uint16 a[maxbc]) int j; for(j = 0; j < BC; j++) a[j] = mc[a[j]]; /* MixColumn */ // uint16 MiniRijndaelAlg::InvMixColumn(uint16 a) return imc[a]; /* InvMixColumn */ // void MiniRijndaelAlg::InvMixColumn(uint16 a[maxbc]) int j; for(j = 0; j < BC; j++) a[j] = imc[a[j]]; /* InvMixColumn */ // int MiniRijndaelAlg::rijndaelKeySched (uint16 k[maxkc],uint16 W[MAXROUNDS+1][MAXBC]) /* Calculate the necessary round keys * The number of calculations depends on keybits and blockbits */ int j, kk, t, rconpointer = 0; uint16 tk[maxkc]; uint16 aux; for(j = 0; j < KC; j++) tk[j] = k[j]; /* copy values into round key array */
88 84 t = 0; for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) W[t / BC][t % BC] = tk[j]; while (t < (ROUNDS+1)*BC) /*for(j = 0; j < KC; j++) printf(" j = %d tk[j]1 = %04x\n",j,tk[j]); for(kk=0; kk<maxrounds+1; kk++) for(j=0; j<maxbc; j++) printf("%04x ",W[kk][j]); printf("\n"); */ /* while not enough round key material calculated */ /* calculate new values */ tk[0] ^= S4[ low16(tk[kc-1]<<4 low4(tk[kc-1]>>12))]; tk[0] ^= rcon[rconpointer++]; // substitution + xor if (KC!= 8) for(j = 1; j < KC; j++) tk[j] ^= tk[j-1]; else for(j = 1; j < KC/2; j++) tk[j] ^= tk[j-1]; tk[kc/2] ^= S4[ low16(tk[kc/2-1])]; // S4() in the middle also for(j = KC/2 + 1; j < KC; j++) tk[j] ^= tk[j-1]; /* copy values into round key array */ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) W[t / BC][t % BC] = tk[j]; //printf(" t1 = %d t2 = %d W = %04x\n",t/BC,t%BC,W[t / BC][t % BC]); return 0; /* rijndaelkeysched */ // uint16 MiniRijndaelAlg::roundConstant(int index) return rcon[index]; // Utils.h #ifndef _UTILS_H_ #define _UTILS_H_ #include "MiniRijndaelAPI.h" #include <cstdio>
89 85 #include <cstdlib> #include <gmp.h> #include <cstring> typedef mpz_t **vsum_t; class Utils public: Utils(); ~Utils(); int printblock(uint16 bb[maxbc]); int printblockd(uint16 bb[maxbc]); int key2rk(uint16 rkk[maxrounds+1][maxbc], uint16 rk[maxrounds+1][maxbc]); int writesteps(uint16 kkey[maxbc],uint32 ill,uint32 iul,char *filename,uint64 vxor[maxsteps][maxbc],int veq[maxsteps][maxbc],float tt,vsum_t vsum); int printsteps(uint16 kkey[maxbc],uint32 ill,uint32 iul,char *filename,uint64 vxor[maxsteps][maxbc],int veq[maxsteps][maxbc],float tt,vsum_t vsum); int ct2v(uint32 const j,uint16 ct[maxbc],uint64 vxor[maxsteps][maxbc], uint64 v_0[maxsteps][maxbc],int veq[maxsteps][maxbc],uint32 const pp,vsum_t vsum); void geraconjuntointegral_1_order(uint16 conjunto[][maxbc],uint16 valorbytesnsaturados); void geraconjuntointegral_4_order(uint16 conjunto[][maxbc],uint16 blocktype); void invertechave(minirijndaelalg* rijndaelalg,uint16 subchave[kc],uint16 chavemestra[kc]); ; #endif //_UTILS_H_ #include "Utils.h" Utils.cpp Utils::Utils() // Utils::~Utils() // void Utils::geraConjuntoIntegral_1_Order(uint16 conjunto[][maxbc],uint16 valorbytesnsaturados) unsigned int i; for(i = 0;i < 16;i++) conjunto[i][0] = (i << 12); conjunto[i][3] = conjunto[i][2] = conjunto[i][1] = valorbytesnsaturados; // void Utils::geraConjuntoIntegral_4_Order(uint16 conjunto[][maxbc],uint16 blocktype)
90 86 unsigned int i = 0; unsigned int v1,v2,v3,v4 = 0; uint16 p1,p2,p3,p4; //permuted values if(blocktype)p1 = 0x0FFF; else p1 = 0; for(v1 = 0;v1 < 16;p1 += 0x1000,v1++) if(blocktype)p2 = 0xF0FF; else p2 = 0; for(v2 = 0;v2 < 16;p2 += 0x100,v2++) if(blocktype)p3 = 0xFF0F; else p3 = 0; for(v3 = 0;v3 < 16;p3 += 0x10,v3++) if(blocktype)p4 = 0xFFF0; else p4 = 0; for(v4 = 0;v4 < 16;p4 += 0x1,i++,v4++) conjunto[i][0] = p1; conjunto[i][1] = p2; conjunto[i][2] = p3; conjunto[i][3] = p4; // void Utils::inverteChave(MiniRijndaelAlg* rijndaelalg,uint16 subchave[kc],uint16 chavemestra[kc]) unsigned int i,j; //variáveis usadas para loops int t; uint16 extendedkey[(kc)*(rounds+1)]; for(i = 0;i < (KC)*(ROUNDS+1);i++) extendedkey[i] = 0; //copia a subchave 5 para o final da chave extendida for(j =0,t=((BC)*(ROUNDS));j < KC;j++,t++) extendedkey[t] = subchave[j]; for(t -= KC+1;t >= 0; t--) if((t % KC) == 0) extendedkey[t] = low16((extendedkey[t+3] << 4) ( low4(extendedkey[t+3]>> 12))); extendedkey[t] = rijndaelalg->substitution(extendedkey[t]); extendedkey[t] ^= extendedkey[t+4];
91 87 extendedkey[t] ^= rijndaelalg->roundconstant(t/kc ); else extendedkey[t] = extendedkey[t+3] ^ extendedkey[t+4]; for(i = 0;i < (KC)*(ROUNDS+1);i++) printf("%x,",extendedkey[i]); printf("\n"); //copia chave mestra for(j =0;j < KC;j++) chavemestra[j] = extendedkey[j]; //
92 Apêndice B Artigo
93 Ataque Quadrado ao Algoritmo Criptográfico AES Paulo Soto de Miranda 30 de março de 2006
94 Abstract The present work is a theoretical and computational analysis of the square attack applied to the criptographic algorithm AES. The theoretical analysis is about the matematical bases of the AES and its attacks, a detailed description of the AES s design and three types of square attack: a first order attack to 4 and 6 rounds and a fourth attack to 5 rounds of the AES. The computational analysis is the implementation of the AES and three kinds of attacks using the C++ programming language. These attacks were elaborated by cryptanalysts and presented in scientific congresses, but its demostration were limited only to the theory. The merit of this work is to demostrate the attacks operation using the computer.
95 1 Resumo Este trabalho é uma análise teórica e computacional de diferentes ataques quadrados aplicados ao algoritmo criptográfico AES. A análise teórica aborda os fundamentos matemáticos usados no AES e nos ataques, a descrição detalhada do projeto do AES e a descrição de três tipos de ataques quadrados: o ataque de primeira ordem sobre 4 e 6 rodadas e o ataque de quarta ordem sobre 5 rodadas do AES. A análise computacional consiste na implementação do AES e dos trê tipos de ataques na linguagem de programação C++. Esses ataques foram elaborados por criptoanalistas e apresentados em congressos científicos, mas suas demostrações se restringiram apenas à teoria. O mérito desse trabalho é demostrar computacionalmente o funcionamento desses ataques. B.1 Introdução A tecnologia da informação tem evoluido muito e englobado várias áreas da sociedade. Algumas dessas áreas lidam com informações muito importantes e sigilosas, como transações bancárias e estratégias governamentais. Logo, o domínio da segurança de dados se tornou essencial. A base para esses serviços de segurança é a criptografia. Ela é um processo usado para transformar um conjunto de dados legíveis quaisquer em um conjunto de dados ininteligível. Essa operação é chamada de cifragem e a sua inversa de decifragem. O algoritmo criptográfico mais avançado é o Rijndael, também chamado de AES, Advanced Encryption Standard. Ele foi criado por dois criptoanalistas belgas chamados Joan Daemen and Vincent Rijmen. Diferente dos algoritmos utilizados anteriormente, o Rijndael tem como base a matemática. Ela provê um maior formalismo ao algoritmo, permitindo provar matematicamente a eficácia dos mecanismos utilizados. Outra vantagem é que, por essas técnicas já terem sido profundamente estudadas, não é necessário criar toda uma nova gama de técnicas de análise específicas para ele, é possível utilizar o embasamento teórico relativo à matemática utilizada. Esse trabalho tem como objetivo analisar as diferentes versões do ataque quadrado ao AES. Essa análise é composta pelo entendimento do ataque, a implementação computacional e observações sobre os resultados. B.2 O Ataque Quadrado O ataque quadrado é uma ténica muito efetiva de criptoanálise para cifradores de bloco. Ele foi concebido como uma ténica dedicada ao algoritmo Square, mas também pode ser usada nos cifradores Rijndael (AES), Twofish e IDEA. Ele é o melhor ataque conhecido contra o AES. Diferentes versões desse ataque foram desenvolvidas, variando a ordem do ataque e o número de rodadas do cifrador. A ordem do ataque diz respeito ao número de bytes do bloco que são saturados. Serão analisados os ataques de primeira ordem para 4 rodadas [6] e 6 rodadas [7] e o ataque de quarta ordem para 5 rodadas [8]. Devido a limitações de capacidade de processamento e tempo, o ataque de primeira ordem sobre 6 rodadas e o ataque de quarta ordem sobre 5 rodadas foram implementados em cima de uma versões reduzida do AES. Essa versões têm a metade do tamanho de bloco e chave e orientada a nibble(4 bits), ao invés de byte. O projeto desse mini-aes está fora do escopo desse trabalho. O ataque implementado sobre esse
96 2 algoritmo tem os mesmos princípios que o implementado sobre o AES padrão, porém a complexidade do ataque é muito menor, o que torna a sua implementação viável. B.2.1 Ataque de primeira ordem sobre 4 rodadas A descrição desse ataque é baseada em [6]. O ataque consiste em criar um conjunto de 256 blocos que são diferentes entre si em apenas uma posição, no elemento a 0,0. Essa posição assume todos os valores possíveis de um byte, de 0 até 255, cada bloco com um valor. As outras 15 posições assumem o mesmo valor em qualquer bloco do conjunto. Posições diferentes podem ter valores distintos, o que se mantém constante é o valor em cada posição específica. Esse conjunto se chama conjunto integral ou conjunto Λ. A posição que assume os valores diferentes se chamada posição saturada ou ativa, e é representada pela letra p, de permutação. As posições que não tém o valor mudado são representadas pela letra c, de constante. A representação do bloco fica assim: p c c c c c c c c c c c : i = 0, 1,..., 255 (B.1) c c c c i Nas subsessões seguinte serão mostradas as transformações que o conjunto integral sofre durante as 4 rodadas da cifragem. B a Rodada A aplicação inicial de AddRoundKey não altera a estrutura do conjunto integral, apenas muda o valor das posições constantes e muda a ordem dos valores da posição saturada, que continua tendo todos os 256 valores dentro do conjunto: A ordem dessas valores não importa, pois trata-se de um conjunto e não de uma sequência ordenada. A transformação ByteSub é uma função injetora, o que faz com que a sua aplicação ao conjunto integral não altere a estrutura do conjunto. A posição saturada sofrerá apenas uma permutação e as posições constantes terão seus valores trocados: p c c c c c c c c c c c : i = 0, 1,..., 255 (B.2) c c c c i A transformação ShiftRow apenas troca a localização dos bytes. Como a posição saturada usada é na primeira linha e ela não sofre deslocamento na transformação, nada é mudado. Mas se a posição saturada fosse em outra linha, ela seria deslocada, mas isso nada afeta a estrutura do conjunto integral. A transformação MixColumn muda toda a coluna que contém a posição saturada. Isso faz com que os outros 3 bytes da coluna passem a ser função da posição saturada. Mas não faz com que a posição saturada pare de assumir os 256 valores possíveis. Para melhor explicar o efeito da MixColumn, a considere como sendo a função MC(x, y, z, w), onde x,y,z e w são as posições de uma coluna. No caso da primeira coluna, a MC vai receber como parâmetro uma permutação e três constantes: MC(p,c,c,c). Como apenas o parâmetro p muda entre os blocos, o resultado do MC vai depender apenas de p. Variando todos os valores possíveis das entradas, , o
97 3 conjunto imagem será igual a p. Nas posições onde os quatro parâmetros são constantes, MC(c, c, c, c), a imagem será uma constante: MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) p c c c MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) p c c c MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(p, c, c, c) MC(c, c, c, c) MC(c, c, c, c) MC(c, c, c, c) i p c c c p c c c (B.3) A transformação AddRoundKey, como foi dito anteriormente, não altera a estrutura do conjunto integral, apenas faz uma permutação da posição saturada. B a Rodada A transformação ByteSub apenas muda o valor de cada byte, mantendo a estrutura do conjunto. A trasformação ShiftRow desloca as posições saturadas, fazendo com que toda coluna contenha uma posição saturada: p c c c c p c c c c p c : i = 0, 1,..., 255 (B.4) c c c p i A trasformação MixColumn opera sobre cada coluna separadamente e faz com que todas as posições do bloco se tornem saturadas: p p p p p p p p p p p p : i = 0, 1,..., 255 (B.5) p p p p i Como foi dito anteriormente, a transformação AddRoundKey não muda a estrutura do conjunto. Portanto, depois de duas rodadas do AES, cada um dos 16 bytes de cada bloco está saturado. B a Rodada Foi visto no passo anterior que as transformações ByteSub, Shift-Row e AddRoundKey não alteram a estrutura do conjunto integral. O mesmo não acontece com a transformação MixColumn. A MixComlumn faz com que cada posição da coluna seja função das quatro posições. Se apenas uma posição estiver saturada, todos os valores dos elementos vão variar de acordo com a posição saturada. Como um elemento saturado pode ter 2 8 valores, os outros três valores também vão variar nessa faixa. Até a segunda rodada existia no máximo um elemento saturado em cada posição da coluna, o que fazia com que a conjunto integral não perdesse sua estrutura. Mas nessa rodada, todos os elementos das colunas estão saturados. Logo, cada elemento de uma coluna tem como valor o resultado da MC com os quatro parâmetros variando: : i = 0, 1,..., 255 MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) b b b b MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) b b b b b b b b : i = 0, 1,..., 255 MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) MC(p, p, p, p) b b b b i i (B.6) i
98 4 A variação dos quatro valores, ( ), resulta em 2 32 possíveis combinações. Essas combinações retornam 2 32 resultados, sendo 2 8 valores distintos distribuidos de forma não uniforme. Como existe apenas 2 8 blocos, resultados não aparecerão, apenas os primeiros 2 8. Como a distribuição dos valores dos resultados não é uniforme, vai acontecer de valores aparecerem repetidos e outros valores não aparecem. Logo, a estrutura do conjunto integral é perdida. Nessa rodada, apesar da estrutura do conjunto integral ter sido quebrada, existe uma propriedade que não é afetada por transformações lineares e será usada como base para o ataque. Essa propriedade é o balanço, que é a soma dos elementos de mesma posição do conjunto integral. A seguinte equação formaliza esse conceito: a 0 i,j a 1 i,j... a 255 i,j 255 a k i,j = 0 k=0 (B.7) O somatório é o ou-exclusivo dos termos. Em qualquer posição do bloco cada bit assume o valor 1 exatamente 128 vezes, fazendo com que a aplicação do ou-exclusivo resulte em 0 bit a bit. Logo, todas as posições do conjunto integral estão balanceadas. Quanto à transformação AddRoundKey, ela também não altera o balanço, pois a mesma subchave é aplicada a todos os blocos do conjunto. Portanto, depois de 3 rodadas do AES, todas as posições dos blocos estão balanceadas. B a Rodada Essa rodada é a última nesse ataque e portanto consiste apenas nas transformações ByteSub, ShiftRow e AddRoundKey. Considerando h como o resultado do terceiro passo, o quarto passo pode ser representado pela seguinte equação: z ShiftRow(ByteSub(h)) K 4 (B.8) onde K 4 é a subchave utilizada no quarto passo. É possível escrever o resultado do terceiro passo da seguinte maneira: h = InvByteSub(InvShiftRow(z K 4 )) = InvByteSub(InvShiftRow(z) InvShiftRow(K 4 )) (B.9) Esse processo pode ser visualizado pela figura B.1. Como foi visto anteriormente, todas as posições de h são balanceadas. Logo, para a subchave K 4 correta, todas as posições de h (Equação B.9) são balanceadas. Caso a subchave seja incorreta, o balanço em uma posição qualquer será incorreto, isto é, diferente de zero. Uma subchave incorreta pode produzir um balanço correto com a probabilidade de 1 256, pois existem 256 valores possíveis para um byte e o zero é um deles. O ataque quadrado está baseado nas observações acima e se resume em buscar exaustivamente a chave usada na cifragem testando a sua corretude através do balanço do conjunto integral. O ataque começa com a obtensão dos blocos do conjunto integral cifrados. Seja z k o k-ésimo bloco do conjunto integral cifrado. É fixado um byte zk i,j e tenta-se encontrar o valor ki,j 4, que é o byte da subchave usado na cifragem desse bloco. Para isso, primeiro é dado um valor aleatório a ki,j 4 e depois é feita a transformação InvShiftRow sobre zi,j k e k4 i,j, e em seguida é aplicado InvByteSub sobre o ou-exclusivo desses dois resultados. Repete-se o processo para todos os blocos do conjunto integral,calcula-se o ou-exclusivo dos resultados e testa-se se a soma é zero.
99 Figura B.1: Ataque 4 rodadas 5
100 6 A operação InvShiftRow pode ser contornada da seguinte forma: [InvShiftRow(z k )] i,j = z k i,(4 i+j)mod 4 (B.10) o que resume a procura do byte da subchave a verificar se a seguinte igualdade é válida: 255 S 1 [zi,(4 i+j)mod k 4 k i,j] = 0 k=0 (B.11) onde S 1 é a caixa-s inversa. Se a igualdade for válida, o valor de ki,j 4 está certo, caso contrário, o valor de ki,j 4 está errado e é dado um novo valor para ele e todo o processo é repetido. Como foi dito anteriormente, esse teste pode retornar um valor errado com probabilidade de O que pode ser feito é usar um segundo conjunto integral no processo, o que diminui a chance de erro para Para obter o resto de K 4 basta repetir o procedimento para os outros bytes. Através desse ataque foi possível obter a subchave K 4. Para obter a chave mestra é necessário inverter o processo de derivação de chave, descrito na sessão 3.5. A complexidade desse ataque é equivalente a 2 15 ( ) cifragens usando 2 9 textos escolhidos. Esse resultado é obtido através da multiplicação do número de bytes da chave a serem encontrados(2 4 ) pela faixa de valores possíveis de um byte da chave(2 8 ), pelo número de indexações da caixa-s para cada byte da chave(2 8 ) e pelo nmero de vezes que tudo isso é feito(2), tudo divido pelo número de indexações presentes em uma cifragem com 4 rodadas(2 6 ). complexidade = ((n o de bytes da chave) (faixa de valores da chave) (n o de indexacoes para cada tentativa de chave)) (n o de conjuntos integrais) ((indexacoes por rodada) (n o de rodadas)) (B.12) B.2.2 Ataque de primeira ordem sobre 6 rodadas Esse ataque é basicamente o ataque sobre 4 rodadas com duas extensões, uma nova rodada no final do cifrador e a outra no início. Nas próximas sessões serão explicadas as extensões e como elas são combinadas para formar o ataque ao AES com 6 rodadas. B Extensão?no final Essa extensão consiste em adicionar uma nova rodada no final do cifrador, que o deixa com 5 rodadas. O ataque é fundamentado sobre o mesmo princípio que o anterior, decifrar o texto cifrado até que os blocos estejam balanceados, o que é uma característica dos blocos cifrados com 3 rodadas. Portanto, nesse ataque é necessário decifrar duas rodadas do AES. Considerando h como o resultado da terceira rodada, z o resultado do quarta rodada e p o resultado da quinta rodada, é possível escrever h da seguinte maneira: h = InvByteSub(InvShiftRow(InvMixColumn(z)) InvShiftRow(InvMixColumn(K 4 ))) z = InvByteSub(InvShiftRow(p) InvShiftRow(K 5 )) O processo pode ser visualizado pela figura B.2. (B.13)
101 Figura B.2: Estensão no final 7
102 8 Para que seja possível fazer as rodadas de decifragem, é necessário conhecer as subchaves empregadas em cada rodada. No caso do ataque, essas subchaves serão descobertas através de uma busca exaustiva. Para cada tentativa de recuperar o h corretamente, uma 5-tupla de bytes terá que ser adivinhada: um byte da subchave da quarta rodada e quatro bytes da subchave da quinta rodada pertencentes à mesma coluna. São necessários 4 bytes da quinta subchave, porque o resultado da InvMixcolumn depende dos 4 bytes da coluna. A equação que representa a relacão posicional entre um byte de h e cada byte da 5-tupla é: h i,j (K 4 i,(4 i+j)mod4, K5 i,(8 2i+j)mod4, K5 i+1,(8 2i+j)mod4, K5 i+2,(8 2i+j)mod4, K5 i+3,(8 2i+j)mod4 ) (B.14) A complexidade desse ataque é de 2 37,7 ( ( ) ) cifragens e 2 32 textos escolhidos. Esse número foi obtido pela seguinte equação: complexidade = ((n o de colunas da chave) (faixa de valores da coluna) ((n o de indexacoes na quinta rodada) + (faixa de valores de um byte da chave da quarta rodada) (n o de indexa?es na quarta rodada))) ((indexacoes por rodada) (n o de rodadas)) (B.15) B Extensão no início Nessa estensão, o ataque acima é estendido com mais uma rodada, mas dessa vez no início do algoritmo. Isso faz com que o ataque tenha eficácia sobre um AES de 6 rodadas. O conjunto de entrada deve será escolhido de modo que o resultado da primeira rodada seja igual à entrada do ataque de 5 rodadas descrito anteriormente, isto é, um conjunto integral dos quais uma posição dos blocos deve ser uma permutação e as outras devem ser constantes. Para isso, é necessário usar um conjunto de entrada de 2 32 blocos com 4 posições saturadas. As posições dos elementos saturandos deve ser tal que, ao passar pela ShiftRow, eles pertencerão à mesma coluna. Essa coluna conterá o elemento saturado no final da rodada. Quando esses 2 32 blocos são cifrados pela rodada adicional, eles produzirão 2 32 blocos dos quais pode ser selecionado um conjunto integral. É possível selecionar 2 8 diferentes conjuntos integrais. Para fazer essa rodada inicial é preciso conhecer os 4 bytes da chave que irão ser combinados com as 4 posições saturadas. Esses bytes são atingidos através de busca exaustiva. Para cada quadrupla de bytes testados, é necessário rodar o ataque anterior. A complexidade do ataque é ( ) cifragens e 2 32 textos escolhidos. Esse resultado é obtido através da multiplicação da faixa de bytes a serem testados nos 4 bytes da primeira subchave(2 32 ) pela complexidade do ataque anterior( ). Esse processo pode ser visualizado pela figura B.3. B.2.3 Ataque de quarta ordem sobre 5 rodadas Esse ataque é composto pelos mesmos passos que o ataque de primeira ordem sobre 4 rodadas, mas com um conjunto de blocos de entrada diferente, um conjunto integral de quarta ordem. Isso significa que o conjunto contém quatro elementos saturados.
103 Figura B.3: Extens? no in?io 9
104 10 Esses 4 bytes podêm ser vistos como uma word que varia de 0 a Logo, para o conjunto integral conter todos os valores posíveis são necessários 2 32 blocos. Para explicar a importância desse ataque é necessário explicar o conceito de invariante. O invariante de um algoritmo é a parte do algoritmo cujo comportamento é possível prever, é a parte até a qual a estrutura dos blocos de entrada não?é perdida. O objetivo de um cifrador é acabar com qualquer estrutura que os blocos de entrada possam ter, fazendo com que a saída do cifrador seja semelhante a um gerador de números aleatórios. Logo, quanto menor o invariante de cifrador, melhor ele é. Com o uso de um conjunto integral de quarta ordem o invariante do cifrador avança mais uma rodada, permitindo estender o ataque ao AES a 5 rodadas. Esse avanço é possível porque o conjunto consegue passar pelo terceiro MixColumn sem perder a sua estrutura. As propriedades do MixColumn referente a isso foram explicadas na subsessão B A complexidade desse ataque é equivalente a ( ) cifragens usando 2 33 textos escolhidos. Esse resultado é obtido através da multiplicação do número de bytes da chave a serem encontrados(2 4 ) pela faixa de valores possíveis de um byte da chave(2 8 ), pelo número de indexações da caixa-s para cada byte da chave(2 32 ) e pelo número de vezes que tudo isso é feito(2), tudo divido pelo número de indexações presentes em uma cifragem com 5 rodadas(2 4.5). complexidade = ((n o de bytes da chave) (faixa de valores da chave) (n o de indexacoes para cada tentativa de chave)) (n o de conjuntos integrais) ((indexacoes por rodada) (n o de rodadas)) (B.16) B.2.4 Conclusão Esse trabalho conseguiu atingir todos os objetivos definidos. Com os estudos feitos nesse trabalho foi possível por em prática as pesquisas feitas pelo Labsec na área de criptoanálise e expandir os conhecimentos sobre criptografia e suas fundamentações matemáticas. A dificuldade enfrentada no desenvolvimento das análises computacionais foi a grande complexidade dos algoritmos de criptoanálise, que requerem uma grande capacidade de processamento, as vezes até proibitiva. Alguns testes implementados podem demorar horas para serem concluídos. Não foi possível implementar ataques sobre um maior número de rodadas do AES, pois eles demandam uma grande capacidade de processamento e tempo, os quais não estavam disponíveis para o desenvolvimento desse trabalho.
Raquel de Araújo Fábio Borges Gerson Nunes. O algoritmo AES: Apresentação e Descrição da Estrutura p.1/23
O algoritmo AES: Apresentação e Descrição da Estrutura Raquel de Araújo Fábio Borges Gerson Nunes O algoritmo AES: Apresentação e Descrição da Estrutura p.1/23 História do Algoritmo Em 1997, o NIST (National
Criptografia e Segurança de Redes Capítulo 5. Quarta Edição por William Stallings
Criptografia e Segurança de Redes Capítulo 5 Quarta Edição por William Stallings Capítulo 5 Advanced Encryption Standard Parece muito simples." É É muito simples. Mas se você não conhece a chave, é praticamente
OTES07 Segurança da Informação Módulo 05b: Criptografia Simétrica: AES/SAES
OTES07 Segurança da Informação Módulo 05b: Criptografia Simétrica: AES/SAES Prof. Charles Christian Miers e-mail:[email protected] Roteiro Criptografia Moderna: Histórico AES e SAES SAES Componentes
TÓPICOS ESPECIAIS EM SEGURANÇA DA INFORMAÇÃO
TÓPICOS ESPECIAIS EM SEGURANÇA DA INFORMAÇÃO AULA 2 CRIPTOGRAFIA AES PROF. MEHRAN MISAGHI 2 AULA 2 CRIPTOGRAFIA AES OBJETIVOS DA AULA Conhecer o histórico do cifrador AES; Compreender a arquitetura do
OSRC001 Segurança em Redes de Computadores Módulo 07: Criptografia Simétrica: AES/SAES
OSRC001 Segurança em Redes de Computadores Módulo 07: Criptografia Simétrica: AES/SAES Prof. Charles Christian Miers e-mail:[email protected] Concurso AES Morte iminente do DES Triple-DES seguro,
Tópicos Especiais em Segurança da Informação. Aula 2 Criptografia AES
Tópicos Especiais em Segurança da Informação Objetivo da Aula Ao final dessa aula, o aluno será capaz de: Discorrer sobre o histórico do cifrador AES; Descrever a arquitetura do cifrador AES; Utilizar
Criptografia e Segurança de Rede Capítulo 4. Quarta Edição por William Stallings
Criptografia e Segurança de Rede Capítulo 4 Quarta Edição por William Stallings Capítulo 4 Corpos Finitos Na manhã seguinte, ao nascer o dia, Star entrou em casa, aparentemente ávida por uma lição. Eu
O padrão de criptografia simétrica AES
O padrão de criptografia simétrica AES Raquel de Araújo de Souza Fábio Borges de Oliveira {rasouza,borges}@lncc.br Resumo Neste trabalho apresentamos o algoritmo AES, atual padrão de criptografia simétrica
Advanced Encryption Standard
Advanced Encryption Standard 5 TÓPICOS ABORAOS 5. ARITMÉTICA E CORPO FINITO 5.2 ESTRUTURA O AES Estrutura geral Estrutura detalhada 5.3 FUNÇÕES E TRANSFORMAÇÃO O AES Transformação subbytes Transformação
SEGURANÇA CRIPTOGRAFIA E SEGURANÇA DE DADOS. As funções de cifra são consideradas totalmente seguras se:
20/02/2016 PROF. FABIANO TAGUCHI http://fabianotaguchi.wordpress.com CRIPTOGRAFIA E SEGURANÇA DE DADOS SEGURANÇA As funções de cifra são consideradas totalmente seguras se: Independente do tempo e do poder
UM HARDWARE IP PARA CRIPTOGRAFIA NO PADRÃO AES-RIJNDAEL
UM HARDWARE IP PARA CRIPTOGRAFIA NO PADRÃO AES-RIJNDAEL Alessandro Girardi, Cláudio Menezes, Cristiano Lazzari, Fernando Paixão Cortes, Juan P. M. Brito, Renato Hentschke, Renato Ubiratan, Ricardo Reis.
O algoritmo AES: Apresentação e Descrição da Estrutura
O algoritmo AES: Apresentação e Descrição da Estrutura Raquel de Araújo de Souza 1, Fábio Borges de Oliveira 1, Gerson Nunes da Cunha 2 1 Laboratório Nacional de Computação Científica Av. Getulio Vargas,
AULA 5: Criptografia e Esteganografia
AULA 5: Criptografia e Esteganografia Criptografia A forma mais utilizada para prover a segurança em pontos vulneráveis de uma rede de computadores é a utilização da criptografia. A criptografia é utilizada
ANÁLISE DO ALGORITMO VENCEDOR DO AES: O RIJNDAEL
ANÁLISE DO ALGORITMO VENCEDOR DO AES: O RIJNDAEL Rafael Antonio da Silva Rosa (IC) Instituto Tecnológico de Aeronáutica (ITA) Pça. Mal. Eduardo Gomes, 50, Vila das Acácias, 12228-901, S. José dos Campos
Fundamentos de Matemática Curso: Informática Biomédica
Fundamentos de Matemática Curso: Informática Biomédica Profa. Vanessa Rolnik Artioli Assunto: sequências e matrizes 05 e 06/06/14 Sequências Def.: chama-se sequência finita ou n-upla toda aplicação f do
Segurança da Informação Aula 6 Principais Algoritmos Simétricos. Criptografia Assimétrica.
Segurança da Informação Aula 6 Principais Algoritmos Simétricos. Criptografia Assimétrica. Prof. Dr. Eng. Fred Sauer [email protected] http://www.fredsauer.com.br Alguns cifradores simétricos: DES, 3DES
M3D4 - Certificados Digitais Aula 2 Certificado Digital e suas aplicações
M3D4 - Certificados Digitais Aula 2 Certificado Digital e suas aplicações Prof. Fernando Augusto Teixeira 1 Agenda da Disciplina Certificado Digital e suas aplicações Segurança Criptografia Simétrica Criptografia
Engloba os criptossistemas clássicos. Outros nomes: (Criptografia...)
Principal característica: utilização da mesma chave para cifrar/decifrar. Engloba os criptossistemas clássicos. Outros nomes: (Criptografia...) convencional de chave única de chave secreta Os procedimentos
(Ciência de Computadores) 2005/ Diga quais dos conjuntos seguintes satisfazem o Princípio de Boa Ordenação
Álgebra (Ciência de Computadores) 2005/2006 Números inteiros 1. Diga quais dos conjuntos seguintes satisfazem o Princípio de Boa Ordenação (a) {inteiros positivos impares}; (b) {inteiros negativos pares};
Criptografia e Segurança em Rede Capítulo 3. William Stallings
Criptografia e Segurança em Rede Capítulo 3 William Stallings Capítulo 3 - Cifras de Blocos e Data Encryption Standard Por toda a tarde, Mungo tinha trabalhado no código de Stern, principalmente com a
Autenticação por par de. chaves assimétricas. Bruno Follmann
Autenticação por par de 1 chaves assimétricas Bruno Follmann 2 Criptografia assimétrica Criada em 1976 por Diffie e Hellman; Também chamada de criptografia de chave pública; Sistema para cifrar e decifrar
Criptografia Pós-Quântica Corretores de Erros
Universidade de São Paulo Criptografia Pós-Quântica P com Códigos C Corretores de Erros Rafael Misoczki IME/USP [email protected] Prof. Dr. Paulo S. L. M. Barreto Poli/USP [email protected]
Renato Martins Assunção
Análise Numérica Renato Martins Assunção DCC - UFMG 2012 Renato Martins Assunção (DCC - UFMG) Análise Numérica 2012 1 / 84 Equação linear Sistemas de equações lineares A equação 2x + 3y = 6 é chamada linear
MATRIZES - PARTE Definição e Manipulação de Matrizes AULA 21
AULA 21 MATRIZES - PARTE 1 21.1 Definição e Manipulação de Matrizes Sabemos como definir variáveis de um novo tipo de dados, denominado vetor, que representam seqüências de valores de um mesmo tipo. Por
Números Inteiros Algoritmo da Divisão e suas Aplicações
Números Inteiros Algoritmo da Divisão e suas Aplicações Diferentemente dos números reais (R), o conjunto dos inteiros (Z) não é fechado para a divisão. Esse não-fechamento faz com que a divisão entre inteiros
x 1 + b a 2 a 2 : declive da recta ;
- O que é a Álgebra Linear? 1 - É a Álgebra das Linhas (rectas). Equação geral das rectas no plano cartesiano R 2 : a 1 x 1 + a 2 = b Se a 2 0, = a 1 a 2 x 1 + b a 2 : m = a 1 : declive da recta ; a 2
Curso Satélite de. Matemática. Sessão n.º 1. Universidade Portucalense
Curso Satélite de Matemática Sessão n.º 1 Universidade Portucalense Conceitos Algébricos Propriedades das operações de números reais Considerem-se três números reais quaisquer, a, b e c. 1. A adição de
Segurança em Redes - 3
Núcleo de Computação Eletrônica Universidade Federal do Rio de Janeiro Segurança em Redes - 3 Luiz Fernando Rust e-mail: INMETRO Tel. (021) 2679-9072 [email protected] [email protected] 11 Criptografia
INE5403 FUNDAMENTOS DE MATEMÁTICA DISCRETA
INE5403 FUNDAMENTOS DE MATEMÁTICA DISCRETA PARA A COMPUTAÇÃO PROF. DANIEL S. FREITAS UFSC - CTC - INE Prof. Daniel S. Freitas - UFSC/CTC/INE/2007 p.1/42 7 - ESTRUTURAS ALGÉBRICAS 7.1) Operações Binárias
O CRIPTO-SISTEMA RIJNDAEL. Sérgio Augusto Prazin de Barros.
O CRIPTO-SISTEMA RIJNDAEL Sérgio Augusto Prazin de Barros. Recife, 29 de julho de 2003 UNIVERSIDADE FEDERAL DE PERNAMBUCO CENTRO DE TECNOLOGIA E GEOCIÊNCIAS PROGRAMA DE PÓS-GRADUAÇÃO EM ENGENHARIA ELÉTRICA
4 ÍNDICE Exemplo de redundância e distância de unicidade... 41
Índice 1 Introdução e motivações 15 1.1 Problemasdesigiloeautenticidade... 16 1.2 Organizaçãodotexto... 18 1.3 O que é criptografia?... 18 1.3.1 CifradeCésar... 18 1.3.2 Criptografia edecriptografia...
Um polinômio com coeficientes racionais é uma escrita formal
Polinômios. Um polinômio com coeficientes racionais é uma escrita formal P (X) = a i X i = a 0 + a 1 X + a 2 X 2 +... + a n X n onde a i Q para todo i {0, 1,..., n}. Isso nos dá uma função f : N Q definida
MAT 1351 : Cálculo para Funções de Uma Variável Real I. Sylvain Bonnot (IME-USP)
MAT 1351 : Cálculo para Funções de Uma Variável Real I Sylvain Bonnot (IME-USP) 2016 1 Informações gerais Prof.: Sylvain Bonnot Email: [email protected] Minha sala: IME-USP, 151-A (Bloco A) Site: ver
n. 1 Matrizes Cayley (1858) As matrizes surgiram para Cayley ligadas às transformações lineares do tipo:
n. Matrizes Foi um dos primeiros matemáticos a estudar matrizes, definindo a ideia de operarmos as matrizes como na Álgebra. Historicamente o estudo das Matrizes era apenas uma sombra dos Determinantes.
MESTRADO PROFISSIONAL EM MATEMÁTICA EM REDE NACIONAL. ENQ Gabarito
MESTRADO PROFISSIONAL EM MATEMÁTICA EM REDE NACIONAL ENQ 2018.1 Gabarito Questão 01 [ 1,25 ::: (a)=0,50; (b)=0,75 ] Isótopos radioativos de um elemento químico estão sujeitos a um processo de decaimento
Software de Telecomunicações. Cifras simétricas por blocos
Software de Telecomunicações Cifras simétricas por blocos Prof RG Crespo Software de Telecomunicações Cifras por bloco : 1/40 Cifras modernas (1) Para dificultar a quebra do código, a chave deve ser o
Criptografia Simétrica e Assimétrica, Hash, e Assinatura Digital
Criptografia Simétrica e Assimétrica, Hash, e Assinatura Digital Segurança da Informação Charles Tim Batista Garrocho Instituto Federal de São Paulo IFSP Campus Campos do Jordão garrocho.ifspcjo.edu.br/sega6
Faculdade de Engenharia da Computação
Faculdade de Engenharia da Computação Disciplina: Modelos Aplicados a Segurança Fundamentos de Criptologia Site : http://www1.univap.br/~wagner/ec.html Prof. Responsáveis Wagner Santos C. de Jesus 1 Conceito
MATEMÁTICA I. Profa. Dra. Amanda L. P. M. Perticarrari
MATEMÁTICA I Profa. Dra. Amanda L. P. M. Perticarrari [email protected] www.fcav.unesp.br/amanda MATEMÁTICA I AULA 1: PRÉ-CÁLCULO Profa. Dra. Amanda L. P. M. Perticarrari CONJUNTOS NUMÉRICOS
Resolução dos Exercícios 31/05-09/06.
Resolução dos Exercícios 31/05-09/06. 1. Seja A um domínio de integridade. Mostre que todo subgrupo finito de U(A) é cíclico. Seja K o corpo de frações de A. Então A é um subanel de K (identificado com
CIFRA DE HILL. Autor: Maycon Pereira de Souza
CIFRA DE HILL Autor: Maycon Pereira de Souza Instituto Federal de Goiás Campus Uruaçu. [email protected] Resumo Vamos falar sobre um método criptográfico conhecido como Cifra de Hill, método este
Faculdade de Engenharia da Computação
Faculdade de Engenharia da Computação Disciplina Segurança Aplicada a Computação Aplicações de Modelos para Segurança Site : http://www1.univap.br/~wagner/ec.html Prof. Responsáveis Wagner Santos C. de
TOCI08 Segurança em Redes de Computadores Módulo 08: Criptografia Assimétrica RSA e ECC
TOCI08 Segurança em Redes de Computadores Módulo 08: Criptografia Assimétrica RSA e ECC Prof. M.Sc. Charles Christian Miers e-mail: [email protected] Roteiro Criptografia Moderna: Diferenças criptografia
Procedimentos e Algorítmos Programas e Linguagens de Programação Tese de Church-Turing Formas de Representação de Linguagens
Procedimentos e Algorítmos Programas e Linguagens de Programação Tese de Church-Turing Formas de Representação de Linguagens 1 Introdução Estudar computação do ponto de vista teórico é sinônimo de caracterizar
Álgebra Linear - Prof. a Cecilia Chirenti. Lista 3 - Matrizes
Álgebra Linear - Prof. a Cecilia Chirenti Lista 3 - Matrizes. Sejam A = C = 0 3 4 3 0 5 4 0 0 3 4 0 3, B = 3, D = 3,. Encontre: a A+B, A+C, 3A 4B. b AB, AC, AD, BC, BD, CD c A t, A t C, D t A t, B t A,
PLANO DE DISCIPLINA DISCIPLINA: Segurança da Informação
UNIVERSIDADE FEDERAL DE UBERLÂNDIA FACULDADE DE COMPUTAÇÃO BACHARELADO EM CIÊNCIA DA COMPUTAÇÃO PLANO DE DISCIPLINA DISCIPLINA: Segurança da Informação ( X ) SEMESTRAL - ( ) ANUAL CÓDIGO: GBC083 PERÍODO:
OTES07 Segurança da Informação Módulo 05c: Criptografia Assimétrica RSA e ECC
OTES07 Segurança da Informação Módulo 05c: Criptografia Assimétrica RSA e ECC Prof. Charles Christian Miers e-mail: [email protected] Breve Histórico Primeiro algoritmo de chave pública foi desenvolvido
Segurança Informática em Redes e Sistemas
Instituto Superior Politécnico de Ciências e Tecnologia Segurança Informática em Redes e Sistemas Prof Pedro Vunge http://pedrovunge.com I Semestre de 2019 SUMÁRIO : Criptografia de Chave Pública ou Assimétrica;
1 bases numéricas. capítulo
capítulo 1 bases numéricas Os números são representados no sistema decimal, mas os computadores utilizam o sistema binário. Embora empreguem símbolos distintos, os dois sistemas formam números a partir
Arquitetura de Computadores I
Arquitetura de Computadores I Aritmética Computacional - Inteiros - Edson Moreno [email protected] http://www.inf.pucrs.br/~emoreno Sumário A unidade lógico-aritmética Representação de números inteiros
Resolução Exe 2.12 Monolítico Recursivo
Resolução Exe 2.12 Monolítico Recursivo Recursivo P R é R 1 onde R 1 def (se T1 então R 2 senão R 3 ) R 2 def F; R 3 R 3 def (se T2 então R 4 senão R 7 ) R 4 def G; R 5 R 5 def (se T1 então R 7 senão R
AULA 08 CRIPTOGRAFIA E SEGURANÇA DE DADOS CRIPTOGRAFIA ASSIMÉTRICA CHAVES E ALGORITMOS 23/04/2016 PROF. FABIANO TAGUCHI
23/04/2016 PROF. FABIANO TAGUCHI http://fabianotaguchi.wordpress.com CRIPTOGRAFIA E SEGURANÇA DE DADOS AULA 08 CRIPTOGRAFIA ASSIMÉTRICA CHAVES E ALGORITMOS 1 CONCEITOS DA TECNOLOGIA CRIPTOGRAFIA ASSIMÉTRICA
Desenvolvimento de Aplicações Distribuídas
Segurança Pontifícia Universidade Católica de Minas Gerais Instituto de Ciências Exatas e Informática DAD (2019/01) Tópicos Apresentação da disciplina Introdução Desafios e características Arquitetura
Dado um inteiro positivo n, definimos U(n) como sendo o conjunto dos inteiros positivos menores que n e primos com n. Não é difícil ver que a
Exemplo (U(n)) Dado um inteiro positivo n, definimos U(n) como sendo o conjunto dos inteiros positivos menores que n e primos com n. Não é difícil ver que a multiplicação módulo n é uma operação binária
Álgebra A - Aula 01 Algoritmo da divisão de Euclides e Algoritmo Euclideano estendido
Álgebra A - Aula 01 Algoritmo da divisão de Euclides e Algoritmo Euclideano estendido Elaine Pimentel Departamento de Matemática, UFMG, Brazil 2 o Semestre - 2010 Introdução Objetivo: estudar o método
Software para Assinatura Digital
UNIVERSIDADE FEDERAL DE SANTA CATARINA CURSO DE SISTEMAS DE INFORMAÇÃO Evandro Araujo de Sousa Software para Assinatura Digital Florianópolis, Novembro de 2004 ii UNIVERSIDADE FEDERAL DE SANTA CATARINA
Segurança em Sistemas Operacionais
Segurança em Sistemas Operacionais A Internet é um divisor águas no tema segurança da informação: Mainframes: segurança por meio do acesso físico; Minicomputadores: segurança por meio subscrição (login
Formação Continuada Nova Eja. Plano de Ação II INTRODUÇÃO
Nome: Armando dos Anjos Fernandes Formação Continuada Nova Eja Plano de Ação II Regional: Metro VI Tutor: Deivis de Oliveira Alves Este plano de ação contemplará as unidades 29 e 30. Unidade 29 I - Matrizes
Operações Fundamentais com Números
Capítulo 1 Operações Fundamentais com Números 1.1 QUATRO OPERAÇÕES Assim como na aritmética, quatro operações são fundamentais em álgebra: adição, subtração, multiplicação e divisão. Quando dois números
A = B, isto é, todo elemento de A é também um elemento de B e todo elemento de B é também um elemento de A, ou usando o item anterior, A B e B A.
Capítulo 1 Números Reais 1.1 Conjuntos Numéricos Um conjunto é uma coleção de elementos. A relação básica entre um objeto e o conjunto é a relação de pertinência: quando um objeto x é um dos elementos
Álgebra Linear Semana 05
Álgebra Linear Semana 5 Diego Marcon 4 de Abril de 7 Conteúdo Interpretações de sistemas lineares e de matrizes invertíveis Caracterizações de matrizes invertíveis 4 Espaços vetoriais 5 Subespaços vetoriais
SSC0112 Organização de Computadores Digitais I
SSC2 Organização de Computadores Digitais I 4ª Aula Revisão de Lógica Digital Profa. Sarita Mazzini Bruschi [email protected] Aula ministrada por Prof. Paulo Sergio Lopes de Souza Revisão de Lógica Digital
Princípio da Localidade Apenas uma parte relativamente pequena do espaço de endereçamento dos programas é acessada em um instante qualquer Localidade
Memória Cache Princípio da Localidade Apenas uma parte relativamente pequena do espaço de endereçamento dos programas é acessada em um instante qualquer Localidade Temporal Um item referenciado tende a
Recursividade, Tentativa e Erro
Recursividade, Tentativa e Erro Túlio Toffolo www.toffolo.com.br Marco Antônio Carvalho [email protected] BCC402 Aula 07 Algoritmos e Programação Avançada Na aula anterior Prova 2 Na aula de hoje Técnicas
Aula 7 - Revisão de Álgebra Matricial
23 de Abril de 2018 // 26 de Abril de 2018 Introdução Objetivo da revisão: revisar a notação matricial, técnicas de álgebra linear e alguns resultados importantes Conteúdos: 1 Vetores e matrizes 2 Operações
Hashing: conceitos. Hashing
Hashing: conceitos hashing é uma técnica conhecida como espalhamento, mapeamento ou randomização que tenta distribuir dados em posições aleatórias de uma tabela (array) associa cada objeto (de um determinado
MAT 1351 : Cálculo para Funções de Uma Variável Real I. Sylvain Bonnot (IME-USP)
MAT 1351 : Cálculo para Funções de Uma Variável Real I Sylvain Bonnot (IME-USP) 2016 1 Informações gerais Prof.: Sylvain Bonnot Email: [email protected] Minha sala: IME-USP, 151-A (Bloco A) Site: ver
Capítulo Propriedades das operações com vetores
Capítulo 6 1. Propriedades das operações com vetores Propriedades da adição de vetores Sejam u, v e w vetores no plano. Valem as seguintes propriedades. Comutatividade: u + v = v + u. Associatividade:
Anéis quocientes k[x]/i
META: Determinar as possíveis estruturas definidas sobre o conjunto das classes residuais do quociente entre o anel de polinômios e seus ideais. OBJETIVOS: Ao final da aula o aluno deverá ser capaz de:
HEP-5800 BIOESTATÍSTICA
HEP-5800 BIOESTATÍSTICA UNIDADE III INFERÊNCIA ESTATÍSTICA : AMOSTRAGEM PROBABILÍSTICA, DISTRIBUIÇÃO AMOSTRAL, INTERVALOS DE CONFIANÇA. Nilza Nunes da Silva Regina T. I. Bernal 2 1. AMOSTRAGEM PROBABILISTICA
Complexidade de Algoritmos
Complexidade de Algoritmos Prof. Diego Buchinger [email protected] [email protected] Prof. Cristiano Damiani Vasconcellos [email protected] Um pouco de Teoria dos Números
Árvores B. Hashing. Estrutura de Dados II Jairo Francisco de Souza
Árvores B Hashing Estrutura de Dados II Jairo Francisco de Souza Funções Hashing Divisão Compressão de chaves alfanuméricas Multiplicação Enlaçamento Deslocado Limite Função Meio-Quadrado Extração Transformação
Matemática Discreta. Fundamentos e Conceitos da Teoria dos Números. Universidade do Estado de Mato Grosso. 4 de setembro de 2017
Matemática Discreta Fundamentos e Conceitos da Teoria dos Números Professora Dr. a Donizete Ritter Universidade do Estado de Mato Grosso 4 de setembro de 2017 Ritter, D. (UNEMAT) Matemática Discreta 4
Universidade Federal de Uberlândia Faculdade de Computação. Representação e aritmética binária
Universidade Federal de Uberlândia Faculdade de Computação Representação e aritmética binária Prof. Renato Pimentel 1 Tipos de informação Representação por meio de sequências binárias: 8 bits (byte) Também
