Operações com Strings: Cifra OTP

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.

Entrada

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.

Saída

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.

Exemplo de Entrada

00010203040506070809
alo mundo!

Exemplo de Saída

9e9292dc968f979c98d7

Exemplo de Entrada

000102030405060708090a0b0c0d0e0f1011121314151617
Universidade de Brasilia

Exemplo de Saída

aa90948a9e888a9193979191d39694d0ad9c8c9f82868089

Exemplo de Entrada

000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
VW5pdmVyc2lkYWRlIGRlIEJyYXNpbGk=

Exemplo de Saída

a9a9c88c9f97af8194c4999faaa5a39ca6a9bf80a2afa391bebeab9481a58add

Exemplo de Entrada

000102030405060708090a0b0c0d0e0f10
e = mc^2 = m*c**2

Exemplo de Saída

9adec0dc9699a7cad7cbd599d991dbdadd

Exemplo de Entrada

000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
?,P0E/"n"#fvIvaI#7t~7rF]B=/H'e|2

Exemplo de Saída

c0d2adccbed5db96d5d59382ba8490b9ccd99992dc98afb5a5dbcaacc4879dd2