CATARINA
CURSO DE GRADUA ¸
C ˜
AO EM CIˆ
ENCIAS DA
COMPUTA ¸
C ˜
AO
Paulo Soto de Miranda
An´
alise do ataque quadrado ao AES
Trabalho de Conclus˜
ao de Curso
Daniel Santana Freitas
ii
Agradecimentos
Agrade¸co principalmente os meus pais que tornaram poss´ıvel a mi-nha entrada na faculdade e que sempre me apoiaram quando precisava.
Ao professor Daniel Santana por me orientar nesse trabalho e tirar minhas d´uvidas com muita aten¸c˜ao.
Aos membros do Labsec que me ajudaram em quest˜oes t´ecnicas e que sempre foram ´otimos companheiros de trabalho.
Resumo
Este trabalho ´e uma an´alise te´orica e computacional de diferentes ataques quadrados aplicados ao algoritmo criptogr´afico AES.
A an´alise te´orica aborda os fundamentos matem´aticos usados no AES e nos ataques, a descri¸c˜ao detalhada do projeto do AES e a descri¸c˜ao de trˆes 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´alise computacional consiste na implementa¸c˜ao do AES e dos trˆes tipos de ataques na linguagem de programa¸c˜ao C++. Esses ataques foram elaborados por criptoanalistas e apresentados em congressos cient´ıficos, mas suas demostra¸c˜oes se restringiram apenas `a teoria. O m´erito desse trabalho ´e demostrar computacionalmente o funcionamento desses ataques.
Sum´
ario
Resumo 1 Sum´ario 2 Lista de Figuras 4 Lista de Tabelas 5 Lista de Siglas 6 1 Introdu¸c˜ao 72 Fundamentos Matem´aticos 10
2.1 Aritm´etica Modular . . . 10
2.2 Aritm´etica em Corpos de Galois . . . 11
2.3 Aritm´etica Polinomial . . . 13 3 O AES 16 3.1 ByteSub . . . 17 3.2 ShiftRow . . . 20 3.3 MixColumn . . . 20 3.4 AddRoundKey . . . 21 3.5 Deriva¸c˜ao de chave . . . 22 4 O Ataque Quadrado 26 4.1 Ataque de primeira ordem sobre 4 rodadas . . . 27
4.1.1 1a Rodada . . . 28
4.1.3 3a Rodada . . . 30
4.1.4 4a Rodada . . . 32
4.2 Ataque de primeira ordem sobre 6 rodadas . . . 35
4.2.1 Extens˜ao no final . . . 35
4.2.2 Extens˜ao no in´ıcio . . . 37
4.3 Ataque de quarta ordem sobre 5 rodadas . . . 39
5 Considera¸c˜oes Finais e Trabalhos Futuros 40 Referˆencias Bibliogr´aficas 41 Apˆendice 42 A C´odigo Fonte 42 B Artigo 88 Abstract 1 B.1 Introdu¸c˜ao . . . 1 B.2 O Ataque Quadrado . . . 1
B.2.1 Ataque de primeira ordem sobre 4 rodadas . . . 2
B.2.2 Ataque de primeira ordem sobre 6 rodadas . . . 6
B.2.3 Ataque de quarta ordem sobre 5 rodadas . . . 8
Lista de Tabelas
Lista de Siglas
AES - Advanced Encryption Standard DES - Data Encryption Standard C/C++ - Linguagem de Programa¸c˜ao NIST - National Institute of Standards RAM - Random Access Memory GF - Galois Field
ByteSub - substitui¸c˜ao byte a byte atrav´es de consultas a uma tabela InvByteSub - trasforma¸c˜ao inversa a ByteSub
ShiftRow - permuta¸c˜ao simples atrav´es de deslocamento de linhas InvShiftRow - trasforma¸c˜ao inversa a ShiftRow
MixColumn - substitui¸c˜ao atrav´es de opera¸c˜oes sobre uma coluna InvMixColumn - trasforma¸c˜ao inversa a MixColumn
AddRoundKey - aplica¸c˜ao de ou-exclusivo entre o bloco e a chave. BS - ByteSub
SR - ShiftRow MC - MixColumn KA - AddRoundKey
Cap´ıtulo 1
Introdu¸c˜
ao
A tecnologia da informa¸c˜ao tem evolu´ıdo muito e englobado v´arias ´areas da sociedade. Algumas dessas ´areas lidam com informa¸c˜oes muito importantes e sigilosas, como transa¸c˜oes banc´arias e estrat´egias governamentais. Logo, o dom´ınio da seguran¸ca de dados se tornou essencial.
A seguran¸ca de dados ´e composta por diversos servi¸cos que prov´em `as informa¸c˜oes do usu´ario:
• Confidencialidade: prote¸c˜ao contra leitura n˜ao autorizada;
• N˜ao-rep´udio: preven¸c˜ao de rep´udio por parte da origem da informa¸c˜ao. Por
exemplo, previni um emissor de uma mensagem negar a sua autoria;
• Autentica¸c˜ao: garantia que a comunica¸c˜ao ´e autentica. Provar que os
comu-nicantes s˜ao realmente quem eles dizem ser;
• Integridade: garantia que a informa¸c˜ao n˜ao foi alterada.
A base para esses servi¸cos de seguran¸ca ´e a criptografia. Ela ´e um processo usado para transformar um conjunto de dados leg´ıveis quaisquer em um conjunto de dados inintelig´ıvel. Essa opera¸c˜ao ´e chamada de cifragem e a sua inversa de decifragem.
8 A criptografia sim´etrica ´e mais r´apida e ´e usada para cifrar grandes quantidades de dados, como arquivos e comunica¸c˜ao entre computadores. A assi-m´etrica ´e mais lenta e ´e mais usada para cifrar pequena quantidade de dados, como resumo (”hash”) de arquivos, que s˜ao usados na assinatura digital.
A criptografia foi inventada na antig¨uidade e vem sendo usada e aprimorada at´e hoje. O principal uso da criptografia sempre foi as guerras. Os paises cifravam os dados para que os inimigos n˜ao os pudesse ler e ent˜ao descobrir os segredos b´elicos. 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ˆencia que faz an´alise desses algoritmos ´e chamada de criptoan´alise. O processo de inventar novos algoritmos e descobrir suas falhas acontece at´e hoje.
O algoritmo sim´etrico mais usado hoje em dia ´e o DES, Data En-cription Standard. A maioria dos sistemas de seguran¸ca tˆem ele como principal algoritmo. Ele foi estudado por v´arios anos por cientistas e foram descobertas v´a-rias falhas. Diante disso, foi necess´ario inventar outro algoritmo, que fosse mais seguro. Para isso, o NIST, National Institute of Standards and Tecnology, a agˆencia respons´avel pela padroniza¸c˜ao de tecnologias da ind´ustria americana, no ano 2000, fez um concurso para eleger um algoritmo para substituir o DES. As principais caracter´ısticas dos candidatos analisadas foram:
• Seguran¸ca geral: resistente contra os ataques j´a conhecidos;
• Custo: o algoritmo dever´a estar dispon´ıvel mundialmente e livre de taxas; • Computacionalmente eficiente: o algoritmo dever´a ser r´apido tanto em
imple-menta¸c˜oes em software e hardware;
• Pouco uso de mem´oria: o algoritmo dever´a usar pouca mem´oria, pois ele
poder´a ser implementado em hardware com pouca mem´oria RAM dispon´ıvel, como os smart cards;
• Flexibilidade: disponibilidade de diferentes tamanhos de bloco e chave e
• Simplicidade: o projeto do algoritmo deve ser simples, o que facilita a sua
implementa¸c˜ao e an´alise.
V´arios algoritmos foram submetidos ao processo de sele¸c˜ao. Os que chegaram `a 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˜ao, que foi batizado de AES, Advanced Encryption Standard. Ele foi criado por dois criptoanalistas belgas chamados Joan Daemen and Vincent Rij-men. Diferente dos algoritmos utilizados anteriormente, o Rijndael tem como base a matem´atica. Ela provˆe um maior formalismo ao algoritmo, permitindo provar matematicamente a efic´acia dos mecanismos utilizados. Outra vantagem ´e que, por essas t´ecnicas j´a terem sido profundamente estudadas, n˜ao ´e necess´ario criar toda uma nova gama de t´ecnicas de an´alise espec´ıficas para ele, ´e poss´ıvel utilizar o em-basamento te´orico relativo `a matem´atica utilizada.
Com o novo algoritmo definido, a pesquisa de criptografia sim´etrica est´a concentrada em analis´a-lo. Alguns ataques j´a foram descobertos e dentre eles o mais eficaz ´e ataque quadrado.
Esse trabalho de conclus˜ao de curso tem como objetivo analisar as diferentes vers˜oes do ataque quadrado ao AES. Essa an´alise ´e composta pelo entendimento do ataque, a implementa¸c˜ao computacional e observa¸c˜oes sobre os resultados.
Cap´ıtulo 2
Fundamentos Matem´
aticos
O algoritmo criptogr´afico AES ´e um conjunto de passos que faz opera¸c˜oes sobre um bloco de dados. Cada bloco nada mais ´e do que um conjunto de n´umeros. Para o projeto do Rijndael, foram empregadas teorias matem´aticas relacionadas com conjuntos e opera¸c˜oes sobre n´umeros, que s˜ao: aritm´etica em corpos de Galois, aritm´etica polinomial e aritm´etica modular. Elas ser˜ao explicadas nas sess˜oes seguintes, de acordo com [2].
2.1
Aritm´
etica Modular
Dado dois inteiros a e b, se n´os dividirmos a por b, teremos o quo-ciente inteiro q e um resto inteiro r, que obedecem `a seguinte rela¸c˜ao:
a = qn + r 0 ≤ r < n; q = ba/nc O resto r ´e tamb´em conhecido como res´ıduo.
Se a ´e um inteiro e n ´e um inteiro positivo, definimos a mod b como o resto de a dividido por b.
Dois inteiros a e b s˜ao ditos ser congruentes m´odulo n, se (a mod n) = (b mod n). Sua nota¸c˜ao ´e a ≡ b mod n.
Definimos Zn como o conjunto de inteiros n˜ao negativos menores
que n:
Esse conjunto ´e referenciado como o conjunto de res´ıduos, ou classes de res´ıduos m´odulo n. Mais precisamente, cada inteiro de Zn representa uma classe
de res´ıduos. Todos n´umeros congruentes entre si m´odulo n pertencem a mesma classe de res´ıduos.
Se for efetuado aritm´etica modular em Zn, as seguintes
proprieda-des ser˜ao seguidas para os inteiros de Zn:
Propriedade Express˜ao
Comutatividade (w + x)mod n = (x + w)mod n (w × x)mod n = (x × w)mod n Associatividade [(w + x) + y]mod n = [w + (x + y)]mod n
[(w × x) × y]mod n = [w × (x × y)]mod n Distributividade [w × (x + y)]mod n = [(w × x) + w × y]mod n
[w + (x × y)]mod n = [(w + x) + w + y]mod n
Identidades (0 + w)mod n = w mod n
(1 × w)mod n = w mod n
Inversa aditiva P ara cada w ∈ Zn, existe um z tal que w + z ≡ 0 mod n
Tabela 2.1: Propriedades da Aritm´etica Modular
A existˆencia de uma inversa multiplicativa depende da condi¸c˜ao de que o n´umero a ser invertido deve ser relativamente primo ao n´umero com o qual est´a calculando o m´odulo, isto ´e, dado um n´umero a e deseja-se calcular seu inverso m´odulo um n´umero n, a−1s´o existir´a se a for relativamente primo a n. Dois n´umeros
s˜ao relativamente primos se eles s´o tiveram o n´umero 1 como divisor comum.
2.2
Aritm´
etica em Corpos de Galois
Na ´algebra abstrata, as opera¸c˜oes s˜ao feitas entre elementos que pertencem a um mesmo conjunto. O resultado dessas opera¸c˜oes dever´a pertencer ao mesmo conjunto dos operadores. Quais opera¸c˜oes satisfazem essa regra dentro de um conjunto vai depender das propriedades do conjunto. Sendo S um conjunto e • uma opera¸c˜ao qualquer definida para esse conjunto, as suas poss´ıveis propriedades s˜ao:
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 a0 tamb´em pertencente a S, tal que a • a0 = a0 • a = e;
5. Comutatividade: a • b = b • a para todo a e b pertencentes a S.
Quando duas opera¸c˜oes est˜ao envolvidas, como • e × (que tamb´em pode ser representada pela concatena¸c˜ao 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´aticos conhecidos como grupos, an´eis e corpos. Cada um deles ´e denotado pelo conjunto de elementos, as opera¸c˜oes definidas para esse conjunto e tamb´em pela gama de propriedades seguidas.
O grupo G, denotado por {G, •}, ´e um conjunto de elementos com uma opera¸c˜ao bin´aria, denotada por •, que associa a cada par (a, b) de elementos pertencentes a G um novo elemento (a • b) tamb´em pertencente a G. S˜ao obedecidas as propriedades de fechamento, associatividade, elemento identidade e o elemento inverso. Um exemplo de grupo ´e (N, +), na qual N ´e o conjunto dos n´umeros naturais e + ´e a opera¸c˜ao de adi¸c˜ao.
Se um grupo tem um n´umero finito de elementos, ele ´e chamado de grupo finito e a sua ordem ´e igual ao n´umero de elementos. Caso contr´ario, ele ´e dito ser um grupo infinito.
Um an´el R, denotado por {R, +, ∗}, ´e um conjunto de elementos com duas opera¸c˜oes bin´arias + e ∗, chamadas de adi¸c˜ao e multiplica¸c˜ao. Em rela¸c˜ao `a +, s˜ao obedecidas todas as propriedades de um grupo mais a comutatividade. J´a em rela¸c˜ao a ∗, apenas as propriedades de fechamento, associatividade e distribu-tividade s˜ao seguidas. O an´el ´e um conjunto com o qual ´e poss´ıvel fazer adi¸c˜ao, subtra¸c˜ao ( soma de um operando com o inverso aditivo do outro) e multiplica¸c˜ao sem sair do conjunto.
inverso em rela¸c˜ao `a ∗. Os conjuntos dos n´umeros racionais, reais e complexos s˜ao exemplos de corpos. Esses s˜ao exemplos de corpos infinitos, a criptografia h´a interesse apenas nos corpos de ordem finita.
Como os dados cifrados tamb´em precisam ser decifrados, ´e neces-s´ario que as opera¸c˜oes executadas durante a cifragem sobre o conjunto de dados de entrada, o bloco, sejam invers´ıveis para que possa ocorrer a decifragem. A exis-tˆencia da inversibilidade dentro de um conjunto usando as opera¸c˜oes de adi¸c˜ao e multiplica¸c˜ao ´e garantida apenas pelos corpos .
Um corpo finito de ordem p ´e um conjunto Zp de inteiros
{0, 1, ..., p − 1}, junto com opera¸c˜oes matem´aticas m´odulo p. Ele ´e denotado por GF (p),onde GF significa Galois Field em honra do matem´atico quem primeiro
es-tudou o assunto.
Como observado na sess˜ao anterior, um elemento de Zp s´o vai ter
uma inversa multiplicativa se ele for relativamente primo a p. Se p for primo, ent˜ao todos os elementos n˜ao zero de Zp ser˜ao relativamente primos a ele e todos ter˜ao
inversos multiplicativos.
Para achar a inversa multiplicativa de um n´umero dentro de um corpo, deve ser usado o algoritmo de Euclides.
O AES usa polinˆomios no qual os coeficientes est˜ao contidos em Zp
e os polinˆomios s˜ao definidos m´odulo um polinˆomio m(x) de ordem n.
2.3
Aritm´
etica Polinomial
No AES s˜ao feitas opera¸c˜oes modulares com polinˆomios. Os coe-ficientes desses polinˆomios fazem parte de um corpo finito. Desse modo ´e poss´ıvel fazer divis˜ao entre polinˆomios, uma vez que a divis˜ao entre dois polinˆomios ´e uma multiplica¸c˜ao de um polinˆomio pelo inverso do outro.
Em analogia `a aritm´etica inteira, n´os podemos escrever
f (x) mod g(x) como sendo o polinˆomio r(x), proveniente do resto da divis˜ao de f (x) por g(x).
14 adi¸c˜ao fica equivalente a opera¸c˜ao ou-exclusivo e a multiplica¸c˜ao `a ”E”. Ela s˜ao extremamente r´apidas de serem efetuadas em computadores.
Um polinˆomio f (x) sobre um corpo F ´e chamado de irredut´ıvel se e somente se f (x) n˜ao poder ser expressado como produto de dois polinˆomios, ambos sobre F , e ambos com grau menor que f (x). Polinˆomios irredut´ıveis tamb´em podem ser chamados de polinˆomios primos.
Na aritm´etica modular, ´e usado um corpo finito da forma GF (2n).
Fazer opera¸c˜oes polinomiais nesse tipo de corpo significa que os coeficientes v˜ao variar de 0 a 1 e que os polinˆomios ter˜ao grau de at´e n − 1. Isso acontece porque as opera¸c˜oes polinomiais s˜ao feitas m´odulo um polinˆomio irredut´ıvel de grau n. Todos os corpos finitos de uma dada ordem s˜ao isom´orficos, isto ´e, mesmo mudando o polinˆomio irredut´ıvel usado no opera¸c˜ao modular, mas mantendo sua ordem, os elementos do corpo ser˜ao os mesmos.
Um polinˆomio f (x) em GF (2n) f (x) = an−1xn−1+ an−2xn−2+ ... + a1x + a0 = n−1 X i=0 aixi
pode ser representado unicamente pelos seus coeficientes bin´arios (an−1an−2...a0). Portanto, um polinˆomio em GF (2n) pode ser representado por um
n´umero bin´ario de tamanho n.
A adi¸c˜ao de polinˆomios corresponde a somar os coeficientes corres-pondentes, e, no caso de polinˆomios em Z2, adi¸c˜ao ´e apenas a opera¸c˜ao ou-exclusivo.
Ent˜ao, a adi¸c˜ao entre dois polinˆomios em GF (2n) corresponde a um opera¸c˜ao
ou-exclusivo bit a bit.
A multiplica¸c˜ao n˜ao ´e t˜ao simples quanto a adi¸c˜ao, mas existe um t´ecnica que a simplifica bastante. Essa t´ecnica ser´a explicada com referˆencia a
GF (28)usando o polinˆomio x8+ x4+ x3+ x + 1, que ´e o corpo finito usado no AES.
A multiplica¸c˜ao de dois polinˆomios consiste em v´arias multiplica-¸c˜oes do primeiro operando por x e em somas dos resultados intermedi´arios,por exem-plo:
A multiplica¸c˜ao de um polinˆomio por x dentro do corpo finito es-pecificado anteriormente pode ser implementada como um deslocamento de 1 bit a esquerda seguido de um ou-exclusivo bit a bit com o n´umero 00011011, que representa o polinˆomio x4 + x3 + x + 1. Essa t´ecnica ´e baseada no fato de que
x8mod x8+ x4+ x3+ x + 1 = x4 + x3 + x + 1. Se o resultado da multiplica¸c˜ao de
Cap´ıtulo 3
O AES
O AES ´e um algoritmo constitu´ıdo por v´arias rodadas. Cada rodada ´e composta por 4 transforma¸c˜oes, uma de permuta¸c˜ao e trˆes de substitui¸c˜ao:
1. ByteSub: usa uma tabela de substitui¸c˜ao para substituir byte por byte do bloco;
2. ShiftRow: uma permuta¸c˜ao simples atrav´es deslocamento de linhas; 3. MixColumn: uma substitui¸c˜ao que usa aritm´etica sobre GF (28);
4. AddRoundKey: aplica¸c˜ao de ou-exclusivo entre o bloco e a chave.
O n´umero de rodadas ´e vari´avel e dependente do tamanho da chave. S˜ao 10 rodadas para chave de 128 bits, 12 para 192 bits e 14 para 256 bits.
A ´ultima rodada n˜ao cont´em a transforma¸c˜ao MixColumn, que foi retirada para que fosse poss´ıvel montar o algoritmo inverso ao AES, que ´e usado na decifragem. A estrutura do AES inverso pode ser visualisada na figura 3.1.
Antes da primeira rodada ´e feita uma AddRoundKey. Apenas a AddRoundKey faz uso da chave. Qualquer outra opera¸c˜ao, aplicada no fim ou no come¸co, ´e revers´ıvel sem conhecimento da chave e portanto, n˜ao adiciona seguran¸ca ao algoritmo.
A seq¨uˆencia de passos pode ser visualizada na figura 3.1.
Figura 3.1: Estrutura do AES
3.1
ByteSub
Essa transforma¸c˜ao consiste em substituir cada byte do bloco por outro byte, que ´e obtido consultando a caixa-S. Ela ´e uma matriz 16×16 que cont´em todos os 256 poss´ıveis valores de 8 bits.
18 4 bits do byte s˜ao usados como valor da linha da matrix e os outros 4 bits como valor para a coluna. A figura 3.2 ilustra essa substitui¸c˜ao.
Figura 3.2: ByteSub [1]
Essa transforma¸c˜ao provˆe a n˜ao linearidade do cifrador. A caixa-S ´e derivada da fun¸c˜ao inversa sobre GF (28), conhecida por ter boas propriedades
n˜ao-lineares. Essa fun¸c˜ao pode ser representada por uma fun¸c˜ao alg´ebrica muito simples, o que permite fazer manipula¸c˜oes alg´ebricas facilmente. Essa maniputa¸c˜oes podem ser usadas para montar ataques como os ataques de interpola¸c˜ao. Para contornar isso, essa fun¸c˜ao ´e combinada com uma transforma¸c˜ao affine invers´ıvel simples. As duas fun¸c˜oes combinadas formam uma express˜ao alg´ebrica complexa, que inibe os ataques [4]. A constru¸c˜ao da caixa-S ´e descrita nos seguintes passos:
1. A caixa-S ´e inicializada com valores de bytes seguindo uma seq¨uˆencia ascen-dente linha por linha. A primeira linha cont´em os valores 00, 01, ..., 0F ; a segunda cont´em 10, 11, ..., 1F ; e assim por diante;
2. Cada byte na caixa-S ´e mapeado para o seu inverso multiplicativo no corpo finito GF (28);
3. ´E aplicada uma transforma¸c˜ao affine particular . Essa transforma¸c˜ao foi es-colhida de modo. Dado um byte rotulado como b7b6b5b4b3b2b1b0, a opera¸c˜ao
escolhida foi:
onde ci ´e um i-´esimo bit da constante 01100011 e o sinal ( 0
) significa que a vari´avel ser´a atualizada com o valor da direita. Ela tamb´em pode ser repre-sentada pela multiplica¸c˜ao das matrizes:
b00 b01 b02 b03 b04 b05 b06 b07 = 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 b0 b1 b2 b3 b4 b5 b6 b7 + 1 1 0 0 0 1 1 0 (3.2)
Para a decifragem ´e usada a opera¸c˜ao InvSubBytes, que ´e seme-lhante a SubByte, por´em usa uma caixa-S inversa. Essa caixa-S inversa ´e contru´ıda aplicando o inverso multiplicativo no corpo finito GF (28) `a caixa-S usanda na
cifra-gem em conjunto da transforma¸c˜ao affine inversa:
b0i = b(i+2)mod 8⊕ b(i+5)mod 8⊕ b(i+7)mod 8⊕ di
onde d ´e 00000101. Cuja representa¸c˜ao matricial ´e:
20
3.2
ShiftRow
Essa transforma¸c˜ao consiste em deslocalar as linhas do bloco ci-clicamente para a esquerda. O n´umero de deslocamentos varia de acordo com a linha. A primeira linha n˜ao ´e deslocada, a segunda ´e deslocada uma posi¸c˜ao, a segunda duas e a terceira posi¸c˜oes. Dessa forma, cada coluna do bloco de sa´ıda ´e composta por bytes de todas as colunas do bloco de entrada. A figura 3.3 ilustra essa transforma¸c˜ao.
Figura 3.3: ShifRow [1]
A transforma¸c˜ao inversa `a ShiftRow ´e chamada de InvShiftRow. Ela ´e semelhante `a ShiftRow, por´em o sentido do deslocamento ´e o inverso, para a direita.
3.3
MixColumn
Essa transforma¸c˜ao opera em cada coluna individualmente. Cada byte da coluna ´e mapeado a um novo valor que ´e uma fun¸c˜ao de todos os quatro bytes da coluna (Figura 3.4).
A tranforma¸c˜ao pode ser definida atrav´es da multiplica¸c˜ao das
ma-trizes: 02 03 01 01 01 02 03 01 01 01 02 03 03 01 01 02 s0,0 s0,1 s0,2 s0,3 s1,0 s1,1 s1,2 s1,3 s2,0 s2,1 s2,2 s2,3 s3,0 s3,1 s3,2 s3,3 = s00,0 s00,1 s00,2 s00,3 s01,0 s01,1 s01,2 s01,3 s02,0 s02,1 s02,2 s02,3 s03,0 s03,1 s03,2 s03,3
Figura 3.4: MixColumn [1]
GF (28). A transforma¸c˜ao MixColumn em uma coluna ´e expressada como:
s00,j = (2 • s0,j) ⊕ (3 • s1,j) ⊕ s2,j ⊕ s3,j
s01,j = s0,j ⊕ (2 • s1,j) ⊕ (3 • s2,j) ⊕ s3,j
s02,j = s0,j ⊕ s1,j⊕ (2 • s2,j) ⊕ (3 • s3,j)
s03,j = (3 • s0,j) ⊕ s1,j ⊕ s2,j⊕ (2 • s3,j)
(3.4)
Essa transforma¸c˜ao est´a fundamentada em multiplica¸c˜oes de linˆomios. Cada elemento de uma coluna se transforma nos coeficientes de um po-linˆomio, que ent˜ao ´e multiplicado pelo polinˆomio c(x)(Equa¸c˜ao 3.5) m´odulo x4 + 1
sobre GF (28).
c(x) =8 030x3+8010x2+8010x +8 020 (3.5)
Esse polinˆomio ´e coprimo a x4+ 1 e portanto invers´ıvel.
3.4
AddRoundKey
22
Figura 3.5: AddRoundKey [1]
3.5
Deriva¸c˜
ao de chave
O algoritmo de deriva¸c˜ao de chave usado na AES consiste em uma fase de expan¸c˜ao e outra de sele¸c˜ao. Na fase de expan¸c˜ao a chave mestra de 128 bits ´e expandida para uma chave de 1408 bits. Essa deriva¸c˜ao ´e 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;
} }
se tranforma em (b,c,d,a). Rcon ´e um conjunto de constantes que s˜ao adicionadas `as subchaves. Para cada subchave, uma constante diferente ´e adicionada, o que previne a cria¸c˜ao de chaves fracas, como acontecia no DES. Na deriva¸c˜ao 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:
RC
ByteSub
Figura 3.6: Deriva¸c˜ao de chave
A fase de sele¸c˜ao ´e simples. As subchaves s˜ao retiradas da chave expandida sequencialmente, a primeira subchave ´e composta do bit 0 at´e bit 127, a segunda subchave do bit 128 at´e o 255, e assim por diante.
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¸c˜ao de chave foi montado de forma que ´e pos-s´ıvel restaurar a chave mestra atrav´es de qualquer subchave. Para isso, ´e necess´ario seguir o caminho inverso da deriva¸c˜ao. A chave mestra corresponde aos primeiros 128 bits da chave estendida. O algoritmo inverso ´e:
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] }
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])
Cap´ıtulo 4
O Ataque Quadrado
O ataque quadrado ´e uma t´ecnica muito efetiva de criptoan´alise para cifradores de bloco. Ele foi concebido como uma t´ecnica dedicada ao algoritmo Square, mas tamb´em pode ser usada nos cifradores Rijndael (AES), Twofish e IDEA. Ele ´e o melhor ataque conhecido contra o AES.
Diferentes vers˜oes desse ataque foram desenvolvidas, variando a ordem do ataque e o n´umero de rodadas do cifrador. A ordem do ataque diz respeito ao n´umero de bytes do bloco que s˜ao saturados. Ser˜ao analisados os ataques de primeira ordem para 4 rodadas [6] e 6 rodadas [7] e o ataque de quarta ordem para 5 rodadas [8].
4.1
Ataque de primeira ordem sobre 4 rodadas
A descri¸c˜ao desse ataque ´e baseada em [6].
Considere a representa¸c˜ao matricial 4 × 4 do bloco de entrada do cifrador: a0,0 a0,1 a0,2 a0,3 a1,0 a1,1 a1,2 a1,3 a2,0 a2,1 a2,2 a2,3 a3,0 a3,1 a3,2 a3,3 (4.1)
O ataque consiste em criar um conjunto de 256 blocos que s˜ao diferentes entre si em apenas uma posi¸c˜ao, no elemento a0,0. Essa posi¸c˜ao assume
todos os valores poss´ıveis de um byte, de 0 at´e 255, cada bloco com um valor. As outras 15 posi¸c˜oes assumem o mesmo valor em qualquer bloco do conjunto. Posi¸c˜oes diferentes podem ter valores distintos, o que se mant´em constante ´e o valor em cada posi¸c˜ao espec´ıfica. Esse conjunto se chama conjunto integral ou conjunto Λ. A posi¸c˜ao que assume os valores diferentes se chamada posi¸c˜ao saturada ou ativa, e ´e representada pela letra p, de permuta¸c˜ao. As posi¸c˜oes que n˜ao tˆem o valor mudado s˜ao representadas pela letra c, de constante. A representa¸c˜ao 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˜oes seguinte ser˜ao mostradas as transforma¸c˜oes que o conjunto integral sofre durante as 4 rodadas da cifragem. Para tal, os quatro blocos:
|00 00 00 00| |01 00 00 00| |02 00 00 00| |03 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00| |00 00 00 00|
de texto em claro ser˜ao tidos como exemplo para mostrar a evolu¸c˜ao dos blocos durante a cifragem. A chave usada ser´a:
28 Tanto a escolha dos quatro blocos de texto quanto a escolha da chave n˜ao tiveram motivo em especial. Esses dados podem ser escolhidos aleatoria-mente.
4.1.1
1
aRodada
A aplica¸c˜ao inicial de AddRoundKey n˜ao altera a estrutura do con-junto integral, apenas muda o valor das posi¸c˜oes constantes e muda a ordem dos valores da posi¸c˜ao saturada, que continua tendo todos os 256 valores dentro do conjunto:
|01 89 01 89| |00 89 01 89| |03 89 01 89| |02 89 01 89| |23 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|
A ordem dessas valores n˜ao importa, pois trata-se de um conjunto e n˜ao de uma sequˆencia ordenada.
A transforma¸c˜ao ByteSub ´e uma fun¸c˜ao injetora, o que faz com que a sua aplica¸c˜ao ao conjunto integral n˜ao altere a estrutura do conjunto. A posi¸c˜ao saturada sofrer´a apenas uma permuta¸c˜ao e as posi¸c˜oes constantes ter˜ao 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 A7| |26 62 26 62| |26 62 26 62| |26 62 26 62| |26 62 26 62| |6E 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¸c˜ao ShiftRow apenas troca a localiza¸c˜ao dos bytes:
|7C A7 7C A7| |63 A7 7C A7| |7B A7 7C A7| |77 A7 7C A7| |62 26 62 26| |62 26 62 26| |62 26 62 26| |62 26 62 26| |6E 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|
em outra linha, ela seria deslocada, mas isso nada afeta a estrutura do conjunto integral.
A transforma¸c˜ao MixColumn muda toda a coluna que cont´em a posi¸c˜ao saturada. Isso faz com que os outros 3 bytes da coluna passem a ser fun¸c˜ao da posi¸c˜ao saturada. Mas n˜ao faz com que a posi¸c˜ao saturada pare de assumir os 256 valores poss´ıveis.
Para melhor explicar o efeito da MixColumn, a considere como sendo a fun¸c˜ao MC(x, y, z, w), onde x,y,z e w s˜ao as posi¸c˜oes de uma coluna. No caso da primeira coluna, a MC vai receber como parˆametro uma permuta¸c˜ao e trˆes constantes: MC(p,c,c,c). Como apenas o parˆametro p muda entre os blocos, o resultado do MC vai depender apenas de p. Variando todos os valores poss´ıveis das entradas, 28.20.20.20, o conjunto imagem ser´a igual a p. Nas posi¸c˜oes onde os
quatro parˆametros s˜ao constantes, MC(c, c, c, c), a imagem ser´a 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) i → p c c c p c c c p c c c p c c c i : i = 0, 1, ..., 255 (4.4) 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 78| |24 78 2D 78| |30 78 2D 78|
A transforma¸c˜ao AddRoundKey, como foi dito anteriormente, n˜ao altera a estrutura do conjunto integral, apenas faz uma permuta¸c˜ao da posi¸c˜ao saturada:
|8D EC 05 64| |B3 EC 05 64| |83 EC 05 64| |9B EC 05 64| |4B 87 C3 0F| |54 87 C3 0F| |4C 87 C3 0F| |40 87 C3 0F| |22 23 AA AB| |3D 23 AA AB| |25 23 AA AB| |29 23 AA AB| |ED 57 65 DF| |CC 57 65 DF| |E4 57 65 DF| |F0 57 65 DF|
4.1.2
2
aRodada
A transforma¸c˜ao ByteSub apenas muda o valor de cada byte, man-tendo a estrutura do conjunto:
30 A trasforma¸c˜ao ShiftRow desloca as posi¸c˜oes saturadas, fazendo com que toda coluna contenha uma posi¸c˜ao saturada:
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 43| |14 CE 6B 43| |17 2E 76 B3| |17 2E 76 20| |17 2E 76 29| |17 2E 76 09| |AC 62 93 26| |AC 62 27 26| |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¸c˜ao MixColumn opera sobre cada coluna separada-mente e faz com que todas as posi¸c˜oes 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 C2 84 23| |D1 DC 30 8D| |C8 FE 28 96| |23 1B B2 F6| |02 61 72 19| |32 7F B5 24| |B3 5D 9D 36| |4B B8 28 76| |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 D7 42 50| |A0 06 D8 70|
Como foi dito anteriormente, a transforma¸c˜ao AddRoundKey n˜ao muda a estrutura do conjunto. Portanto, depois de duas rodadas do AES, cada um dos 16 bytes de cada bloco est´a saturado.
|AB 33 9F 5B| |CB 2D 2B F5| |D2 0F 33 EE| |39 EA A9 8E| |02 54 51 87| |32 4A 96 BA| |B3 68 BE A8| |4B 8D 0B E8| |76 4A 4E 37| |46 68 3D A4| |C7 0E 0D AD| |3F 3A 22 8D| |40 BB B2 31| |10 87 06 A2| |88 C3 1E AB| |9B 12 84 8B|
4.1.3
3
aRodada
Foi visto no passo anterior que as transforma¸c˜oes ByteSub, Shift-Row e AddRoundKey n˜ao alteram a estrutura do conjunto integral. O mesmo n˜ao acontece com a transforma¸c˜ao MixColumn.
elementos v˜ao variar de acordo com a posi¸c˜ao saturada. Como um elemento saturado pode ter 28 valores, os outros trˆes valores tamb´em v˜ao variar nessa faixa.
At´e a segunda rodada existia no m´aximo um elemento saturado em cada posi¸c˜ao da coluna, o que fazia com que a conjunto integral n˜ao perdesse sua estrutura. Mas nessa rodada, todos os elementos das colunas est˜ao saturados. Logo, cada elemento de uma coluna tem como valor o resultado da MC com os quatro parˆametros 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 → b b b b b b b b b b b b b b b b i : i = 0, 1, ..., 255 (4.7) A varia¸c˜ao dos quatro valores, (28.28.28.28), resulta em 232poss´ıveis
combina¸c˜oes. Essa combina¸c˜oes retornam 232 resultados, sendo 28 valores distintos
distribuidos de forma n˜ao uniforme. Como existe apenas 28 blocos, 232− 28
resul-tados n˜ao aparecer˜ao, apenas os primeiros 28. Como a distribui¸c˜ao dos valores dos
resultados n˜ao ´e uniforme, vai acontecer de valores aparecerem repetidos e outros valores n˜ao aparecem. Logo, a estrutura do conjunto integral ´e perdida.
Nessa rodada, apesar da estrutura do conjunto integral ter sido quebrada, existe uma propriedade que n˜ao ´e afetada por transforma¸c˜oes lineares e ser´a usada como base para o ataque. Essa propriedade ´e o balan¸co, que ´e a soma dos elementos de mesma posi¸c˜ao do conjunto integral. A seguinte equa¸c˜ao formaliza esse conceito:
a0i,j⊕ a1i,j ⊕ ... ⊕ a255i,j ≡
255
X
k=0
aki,j = 0 (4.8)
O somat´orio ´e o ou-exclusivo dos termos. Em qualquer posi¸c˜ao do bloco cada bit assume o valor 1 exatamente 128 vezes, fazendo com que a aplica¸c˜ao do ou-exclusivo resulte em 0 bit a bit. Logo, todas as posi¸c˜oes do conjunto integral est˜ao balanceadas. Quanto `a transforma¸c˜ao AddRoundKey, ela tamb´em n˜ao altera o balan¸co, pois a mesma subchave ´e aplicada a todos os blocos do conjunto. Portanto, depois de 3 rodadas do AES, todas as posi¸c˜oes dos blocos est˜ao balanceada. Os estado dos blocos exemplares depois da ByteSub, ShiftRow, MixColumn e AddRoundKey, respectivamente, s˜ao:
32 |09 EA 37 C7| |CA 17 6F 3A| |C4 2E 72 62| |14 C9 5F 3D| |62 C3 DB 39| |1F D8 F1 E6| |B5 76 C3 28| |12 87 D3 19| |20 D1 17 77| |D6 90 F4 23| |45 AE C2 6D| |5D 2B 9B B3| |2F 9A 38 D6| |27 49 5A 45| |D7 95 C6 AB| |93 5D 75 80| |C7 09 EA 37| |3A CA 17 6F| |62 C4 2E 72| |3D 14 C9 5F| |4C 66 46 0A| |42 83 B3 98| |0B 54 28 3E| |6D 21 B7 23| |94 C6 57 81| |FB F2 FB 00| |3F 51 23 66| |3B 22 A8 A0| |4E 26 99 A0| |C9 9F 88 FE| |E3 BE E4 9E| |35 2A E2 50| |3C 07 96 84| |A4 25 88 89| |92 32 06 5A| |82 CC 09 A6| |59 82 B9 8D| |57 67 4C 1F| |1E B0 D7 B9| |78 C5 48 A4| |DE B9 0B 43| |B1 8D A7 C2| |75 2E 7F A4| |71 5D F4 62| |87 7E 42 27| |00 C7 53 79| |2A E6 3F 19| |FC 72 39 D7| |BB 94 59 B0| |23 B6 47 BD| |15 A1 C9 6E| |05 5F C6 92|
4.1.4
4
aRodada
Essa rodada ´e a ´ultima nesse ataque e portanto consiste apenas nas transforma¸c˜oes ByteSub, ShiftRow e AddRoundKey.
Considerando h como o resultado do terceiro passo, o quarto passo pode ser representado pela seguinte equa¸c˜ao:
z ≡ Shif tRow(ByteSub(h)) ⊕ K4 (4.9)
onde K4 ´e a subchave utilizada no quarto passo.
´
E poss´ıvel escrever o resultado do terceiro passo da seguinte ma-neira:
h = InvByteSub(InvShif tRow(z ⊕ K4))
= InvByteSub(InvShif tRow(z) ⊕ InvShif tRow(K4)) (4.10)
Esse processo pode ser visualizado pela figura B.1.
Como foi visto anteriormente, todas as posi¸c˜oes de h s˜ao balance-adas. Logo, para a subchave K4 correta, todas as posi¸c˜oes de h (Equa¸c˜ao B.9) s˜ao
balanceadas. Caso a subchave seja incorreta, o balan¸co em uma posi¸c˜ao qualquer ser´a incorreto, isto ´e, diferente de zero. Uma subchave incorreta pode produzir um balan¸co correto com a probabilidade de 1
256, pois existem 256 valores poss´ıveis para
um byte e o zero ´e um deles.
34 sume em buscar exaustivamente a chave usada na cifragem testando a sua corretude atrav´es do balan¸co do conjunto integral.
O ataque come¸ca com a obtens˜ao dos blocos do conjunto integral cifrados. Seja zk o k-´esimo bloco do conjunto integral cifrado. ´E fixado um byte
zk
i,j e tenta-se encontrar o valor ki,j4 , que ´e o byte da subchave usado na cifragem
desse bloco. Para isso, primeiro ´e dado um valor aleat´orio a k4
i,j e depois ´e feita
a transforma¸c˜ao InvShiftRow sobre zk
i,j e k4i,j, e em seguida ´e 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 ´e zero.
A opera¸c˜ao InvShiftRow pode ser contornada da seguinte forma: [InvShif tRow(zk)]i,j = zi,(4−i+j)mod 4k (4.11)
o que resume a procura do byte da subchave a verificar se a seguinte igualdade ´e v´alida: 255 X k=0 S−1[zk i,(4−i+j)mod 4⊕ ki,j] = 0 (4.12)
onde S−1 ´e a caixa-S inversa. Se a igualdade for v´alida, o valor de k4
i,j est´a certo,
caso contr´ario, o valor de k4
i,j est´a errado e ´e dado um novo valor para ele e todo o
processo ´e repetido. Como foi dito anteriormente, esse teste pode retornar um valor errado com probabilidade de 1
256. O que pode ser feito ´e usar um segundo conjunto
integral no processo, o que diminui a chance de erro para 1 − 2−16. Para obter o
resto de K4 basta repetir o procedimento para os outros bytes.
Atrav´es desse ataque foi poss´ıvel obter a subchave K4. Para obter
a chave mestra ´e necess´ario inverter o processo de deriva¸c˜ao de chave, descrito na sess˜ao 3.5.
A complexidade desse ataque ´e equivalente a 215(24.28.28.2
24.22 ) cifragens
usando 29 textos escolhidos. Esse resultado ´e obtido atrav´es da multiplica¸c˜ao do
n´umero de bytes da chave a serem encontrados(24) pela faixa de valores poss´ıveis
de um byte da chave(28), pelo n´umero de indexa¸c˜oes da caixa-S para cada byte da
de indexa¸c˜oes presentes em uma cifragem com 4 rodadas(26).
complexidade = ((no de bytes da chave) × (f aixa de valores da chave) × (node indexacoes para cada tentativa de chave)) × (node conjuntos integrais)
÷ ((indexacoes por rodada) × (node rodadas))
(4.13)
4.2
Ataque de primeira ordem sobre 6 rodadas
Esse ataque ´e basicamente o ataque sobre 4 rodadas com duas ex-ten¸c˜oes, uma nova rodada no final do cifrador e a outra no in´ıcio. Nas pr´oximas sess˜oes ser˜ao explicadas as extens˜oes e como elas s˜ao combinadas para formar o ataque ao AES com 6 rodadas.
4.2.1
Extens˜
ao no final
Essa extens˜ao consiste em adicionar uma nova rodada no final do cifrador, que o deixa com 5 rodadas. O ataque ´e fundamentado sobre o mesmo prin-c´ıpio que o anterior, decifrar o texto cifrado at´e que os blocos estejam balanceados, o que ´e uma caracter´ıstica dos blocos cifrados com 3 rodadas. Portanto, nesse ataque ´e necess´ario 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, ´e poss´ıvel escrever h da seguinte maneira:
h = InvByteSub(InvShif tRow(InvM ixColumn(z)) ⊕ InvShif tRow(InvM ixColumn(K4)))
z = InvByteSub(InvShif tRow(p) ⊕ InvShif tRow(K5))
(4.14) O processo pode ser visualizado pela figura B.2.
36
pertencentes `a mesma coluna. S˜ao necess´arios 4 bytes da quinta subchave , porque o resultado da InvMixcolumn depende dos 4 bytes da coluna.
A equa¸c˜ao que representa a relac˜ao posicional entre um byte de h e cada byte da 5-tupla ´e:
hi,j → (Ki,(4−i+j)mod44 , Ki,(8−2i+j)mod45 , Ki+1,(8−2i+j)mod45 , Ki+2,(8−2i+j)mod45 , Ki+3,(8−2i+j)mod45 )
(4.15) A complexidade desse ataque ´e de 237,7(4.232.(4+28.4)
24.5 ) cifragens e 232
textos escolhidos. Esse n´umero foi obtido pela seguinte equa¸c˜ao:
complexidade = ((node colunas da chave) × (f aixa de valores da coluna)
× ((node indexacoes na quinta rodada)
+ (f aixa de valores de um byte da chave da quarta rodada)
× (node indexaes na quarta rodada)))
÷ ((indexacoes por rodada) × (node rodadas))
(4.16)
4.2.2
Extens˜
ao no in´ıcio
Nessa estens˜ao, o ataque acima ´e extendido com mais uma rodada, mas dessa vez no in´ıcio do algoritmo. Isso faz com que o ataque tenha efic´acia sobre um AES de 6 rodadas.
O conjunto de entrada deve ser escolhido de modo que o resultado da primeira rodada seja igual `a entrada do ataque de 5 rodadas descrito anteri-ormente, isto ´e, um conjunto integral dos quais uma posi¸c˜ao dos blocos deve ser uma permuta¸c˜ao e as outra devem ser constantes. Para isso, ´e necess´ario usar um conjunto de entrada de 232 blocos com 4 posi¸c˜oes saturadas.
As posi¸c˜oes dos elementos saturandos deve ser tal que, ao passar pela ShiftRow, eles pertencer˜ao a mesma coluna. Essa coluna conter´a o elemento saturado no final da rodada. Quando esses 232 blocos s˜ao cifrados pela rodada
adicional, eles produzirem 232 blocos dos quais pode ser selecionado um conjunto
integral. ´E poss´ıvel selecionar 28 diferentes conjuntos integrais.
38 atrav´es de busca exaustiva. Para cada quadrupla de bytes testados, ´e necess´ario rodar o ataque anterior.
A complexidade do ataque ´e 269.7(232.237.7) cifragens e 232 textos
escolhidos. Esse resultado ´e obtido atrav´es da multiplica¸c˜ao da faixa de bytes a serem testados nos 4 bytes da primeira subchave(232) pela complexidade do ataque
anterior(237.7).
Esse processo pode ser visualizado pela figura B.3.
4.3
Ataque de quarta ordem sobre 5 rodadas
Esse ataque ´e composto pelos mesmos passos que o ataque de pri-meira 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´em quatro elementos saturados. Esses 4 bytes podem ser vistos como uma word que varia de 0 a 232 − 1. Logo, para o conjunto integral conter todos os valores poss´ıveis s˜ao
necess´arios 232 blocos.
Para explicar a importˆencia desse ataque ´e necess´ario explicar o conceito de invariante. O invariante de um algoritmo ´e a parte do algoritmo cujo comportamento ´e poss´ıvel prever, ´e a parte at´e a qual estrutura dos blocos de entrada n˜ao ´e perdida. O objetivo de um cifrador ´e 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´umeros aleat´orios. Logo, quanto menor o invariante de cifrador, melhor ele ´e.
Com o uso de um conjunto integral de quarta ordem o invariante do cifrador avan¸ca mais uma rodada, permitindo extender o ataque ao AES a 5 rodadas. Esse avan¸co ´e 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˜ao B.2.1.3.
A complexidade desse ataque ´e equivalente a 238.7(24.28.232.2
24.5 )
cifra-gens usando 233 textos escolhidos. Esse resultado ´e obtido atrav´es da multiplica¸c˜ao
do n´umero de bytes da chave a serem encontrados(24) pela faixa de valores poss´ıveis
de um byte da chave(28), pelo n´umero de indexa¸c˜oes da caixa-S para cada byte da
chave(232) e pelo n´umero de vezes que tudo isso ´e feito(2), tudo divido pelo n´umero
de indexa¸c˜oes presentes em uma cifragem com 5 rodadas(24.5).
complexidade = ((no de bytes da chave) × (f aixa de valores da chave)
× (node indexacoes para cada tentativa de chave))
× (node conjuntos integrais)
÷ ((indexacoes por rodada) × (node rodadas))
Cap´ıtulo 5
Considera¸c˜
oes Finais e Trabalhos
Futuros
Esse trabalho conseguiu atingir todos os objetivos definidos. Com os estudos feitos nesse trabalho foi poss´ıvel por em pr´atica as pesquisas feitas pelo Labsec na ´area de criptoan´alise e expandir os conhecimentos sobre criptografia e suas fundamenta¸c˜oes matem´aticas.
A dificuldade enfrentada no desenvolvimento das an´alises compu-tacionais foi a grande complexidade dos algoritmos de criptoan´alise, que requerem uma grande capacidade de processamento, as vezes at´e proibitiva. Alguns testes implementados podem demorar horas para serem conclu´ıdos. N˜ao foi poss´ıvel im-plementar ataques sobre um maior n´umero de rodadas do AES, pois eles demandam uma grande capacidade de processamento e tempo, os quais n˜ao estavam dispon´ıveis para o desenvolvimento desse trabalho.
Esse trabalho pode ser expandido visando amenizar o problema apresentado a cima. As solu¸c˜oes poss´ıveis s˜ao:
• Desenvolvimento de uma aplica¸c˜ao que distribua o processamento dos ataques
entre v´arios computadores, tanto para processamento dedicado e n˜ao dedicado.
Referˆ
encias Bibliogr´
aficas
[1] WIKIPEDIA. Advanced Encryption Standard. July 2005. Dispon´ıvel em:
<http://en.wikipedia.org/wiki/AES>.
[2] STALLINGS, W. Cryptography and Network Security - Principles and Pratice. [S.l.]: Alan Apt, 2003.
[3] NIST. AES Implementation. Dispon´ıvel em:
<http://csrc.nist.gov/encryption/aes/rijndael/rijndael-unix-refc.tar>.
[4] RIJMEN, J. D. V. The Disign of Rijndael. [S.l.]: Springer-Verlag, 2002. [5] RIJNMEN, J. D. V. Aes proposal: Rijndael. 1999.
[6] BARRETO, P. O ataque quadrado. Dispon´ıvel em:
<http://planeta.terra.com.br/informatica/paulobarreto/quadrado.pdf>.
[7] LUCKS, S. Attacking seven rounds of rijndael under 192-bit and 256-bit keys.
AES Candidate Conference 2000, p. 215–229, 2000.
Apˆ
endice A
C´
odigo Fonte
1Order4Rounds.cpp
#include <cstdio> #include <cstdlib> #include "RijndaelAPI.h" #include "RijndaelAlg.h" #include "conf.h"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´aveis usadas para loops
//necess´ario 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
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]++;
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) */
/* 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:
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;
}
//---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’);
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) {
/* 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; }
50
/* parse rectangular array into output ciphertext bytes */ for(t = 0; t < 4; t++)
outBuffer[4*j+t] = (BYTE) block[t][j]; }
} break;
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;
}
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; }
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; }
RijndaelAlg.h
#define _RIJNDAELALG_H_
#define MAXBC (256/32) #define MAXKC (256/32) #define MAXROUNDS 14
typedef unsigned char word8; typedef unsigned short word16; typedef unsigned long 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]);
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_
RijndaelAlg.cpp
#include "RijndaelAlg.h" #include "boxes-ref.dat" #include <stdio.h>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) {