Neste exercício, você colocará em prática alguns conhecimentos de manipulação de strings e de codificação através da técnica criptográfica chamada Cifra OTP (One-time Pad) ou Cifra de Uso Único.
Em criptografia, a cifra OTP, também denominada por cifra de uso único, é um algoritmo criptográfico simétrico para o qual há uma prova de segurança de sua robustez, o que lhe confere a característica de ser considerado inquebrável.
Um algoritmo criptográfico pode ser entendido como uma função matemática que recebe como entradas uma chave e uma mensagem (texto claro) a ser protegida; como saída, essa função gera uma mensagem cifrada. Um algoritmo criptográfico seguro é capaz de proteger o sigilo da mensagem, ou seja, um atacante com acesso à mensagem cifrada terá dificuldades para recuperar a mensagem original (texto claro).
Um algoritmo criptográfico simétrico é todo aquele que exige que a chave usada para cifrar a mensagem (chave de cifração) seja exatamente a mesma usada para decifrá-la. Para algoritmos simétricos, apenas aqueles que conhecem a chave de cifração serão capazes de decifrar a mensagem cifrada e recuperar o texto claro.
Na criptografia moderna, parte-se do princípio de que o algoritmo de cifração não deve ser escondido. Dessa forma, adversários interessados em tomar conhecimento do conteúdo do texto claro também têm o conhecimento do algoritmo, mas não conhecem a chave de cifração. Obviamente, por se tratar de um modelo de segurança em que o canal de comunicação é considerado inseguro, o adversário já tem conhecimento da mensagem cifrada e poderá tentar, livremente, decifrá-la testando chaves.
Para conferir segurança nesse modelo de ataque, ou seja, para que o sigilo da mensagem não seja violado pelo adversário, o emissor da mensagem tem que ser bastante cuidadoso para impedir com que o adversário tenha acesso à chave de cifração usada para cifrar (proteger) a mensagem. Obviamente, os mesmos cuidados tem de ser adotados pelo receptor da mensagem cifrada com um algoritmo simétrico: ele também precisará manipular a mesma chave de cifração para conseguir decifrar e recuperar o texto claro ou a mensagem.
É possível afirmar que a segurança depende de um algoritmo criptográfico robusto (e já conhecido pelo adversário) e, também, de propriedades básicas da chave de cifração: por exemplo, se ela for trivial (datas de aniversário, nomes de pets, etc.) ou pertencer a um conjunto de número pequeno de chaves possíveis, o adversário poderá fazer uma busca exaustiva, tentando decifrar a mensagem cifrada com chaves do conjunto até que a mensagem decifrada gerada pelo algoritmo seja inteligível e a cifração seja revertida. Esse é o famoso ataque de força bruta.
Para a cifra OTP, o algoritmo é bastante simples (será descrito a seguir e implementado por você!) e a segurança é fortemente dependente da seguintes características da chave: - ela deverá ser comunicada de forma segura ao receptor; - ela deverá ser usada apenas uma vez; - ela deverá ser aleatória (imprevisível); - ela deverá ter comprimento (em bits) igual ou maior do que o da mensagem (texto claro) que será protegida pelo algoritmo.
O algoritmo (one-time pad) opera combinando cada bit (ou byte) do texto claro com o bit (ou byte) correspondente da chave usando operação de soma modular. Em termos computacionais, para o escopo deste exercício, a soma modular pode ser implementada através do ou-exclusivo entre os respectivos bits da mensagem e da chave.
Observando os requisitos das chaves e respeitando a operação correta do algoritmo, é possível afirmar que o OTP é o único algoritmo de cifração considerado inquebrável de acordo com os princípios da teoria da informação.
Sua aplicação deverá receber em entrada em console uma string codificada em hexadecimal (chave) e uma string (mensagem ou texto claro) de até 32 bytes/caracteres e retornar a mensagem cifrada usando a chave e o texto claro como parâmetros na cifra OTP.
Para gerar a saída em formato imprimível em console, você deverá inverter cada um dos bytes da mensagem cifrada e, na sequência, codificá-los no formato hexadecimal.
A entrada é composta por duas strings de até 32 bytes/caracteres de comprimento, cada uma apresentada em uma linha separada. A primeira string, a string da chave, é codificada em hexadecimal.
A saída é uma string cifrada usando a cifra OTP. Cada byte da saída a ser impressa deverá ser codificado em hexadecimal. Não se esqueça: cada um dos bits da mensagem cifrada deverá ser invertido antes da codificação de saída.
00010203040506070809
alo mundo!
9e9292dc968f979c98d7
000102030405060708090a0b0c0d0e0f1011121314151617
Universidade de Brasilia
aa90948a9e888a9193979191d39694d0ad9c8c9f82868089
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
VW5pdmVyc2lkYWRlIGRlIEJyYXNpbGk=
a9a9c88c9f97af8194c4999faaa5a39ca6a9bf80a2afa391bebeab9481a58add
000102030405060708090a0b0c0d0e0f10
e = mc^2 = m*c**2
9adec0dc9699a7cad7cbd599d991dbdadd
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
?,P0E/"n"#fvIvaI#7t~7rF]B=/H'e|2
c0d2adccbed5db96d5d59382ba8490b9ccd99992dc98afb5a5dbcaacc4879dd2