DEV Community

Matheus 🇧🇷
Matheus 🇧🇷

Posted on

CS50 : S2 | Cifra de César - Parte 1

Cifra de César

Em criptografia, a Cifra de César, também conhecida como cifra de troca, código de César ou troca de César, é uma das mais simples e conhecidas técnicas de criptografia. É um tipo de cifra de substituição na qual cada letra do texto é substituída por outra, que se apresenta no alfabeto abaixo dela um número fixo de vezes. Por exemplo, com uma troca de três posições, A seria substituído por D, B se tornaria E, e assim por diante. O nome do método é em homenagem a Júlio César, que o usou para se comunicar com os seus generais.
-- Wikipedia

Nestes problemas que seguem, o algoritmo de César criptografa mensagens rotacionando as letras de acordo com k posições. Veremos abaixo, nas etapas como transferimos aquela fórmula matemática para o nosso código.

Quebrando o código

  • Pseudocódigo
    1) Receber do usuário uma chave que corresponderá em quantas posições vai girar
    2) Receber do usuário uma mensagem
    3) Iterar sobre cada letra da mensagem

    • Se for maiúscula, preservar, e trocar o caracter de acordo com a chave.
    • Se for minúscula, preservar, e trocar o caracter de acordo com a chave
    • Se não for uma letra, preservar o caracter da mensagem original 4) Imprimir mensagem criptografada em tela
  • Código em C

#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

void stringCipher(string text, int key);

int main(int argc, string argv[])
{
    if(argc != 2) {
        printf("Usage: ./caesar key\n");
        return 1;
    }

    int key = atoi(argv[1]);

    string plaintext = get_string("plaintext: ");
    stringCipher(plaintext, key);
}

void stringCipher(string text, int key) {
    char cypher[strlen(text)];

    string lowerAlphabet = "abcdefghijklmnopqrstuvwxyz";
    string upperAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    for(int i = 0; i < strlen(text); i++) {
        if(isalpha(text[i])) {
            if(islower(text[i])) {
                int position = text[i] - 97;
                int c = (position + key) % 26;
                cypher[i] = lowerAlphabet[c];
            } else if(isupper(text[i])) {
                int position = text[i] - 65;
                int c = (position + key) % 26;
                cypher[i] = upperAlphabet[c];
            }
        } else {
                cypher[i] = text[i];
        }
    }
    printf("ciphertext: %s\n", cypher);
}
Enter fullscreen mode Exit fullscreen mode

Recebendo a Chave do usuário

Na aula 2 vimos sobre a Interface de Linha de Comando e como podemos receber argumentos do usuário através do argv[].

Sabendo-se que toda informação que vem pelo argv[] é do tipo string (por conta do cs50.h). Precisamos converter para o tipo int, para que seja um número, e assim, usarmos na fórmula matemática. Para isto, usaremos a função atoi() que faz parte da biblioteca stdlib.h.

Assim, quando o usuário entrar com um argumento, esse número não será uma string, e sim um número inteiro.

int key = atoi(argv[1]);

Função para a Criptografia

Agora vamos falar sobre a função que faz a mágica acontecer.

void stringCipher(string text, int key) {
    char cypher[strlen(text)];

    string lowerAlphabet = "abcdefghijklmnopqrstuvwxyz";
    string upperAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    for(int i = 0; i < strlen(text); i++) {
        if(isalpha(text[i])) {
            if(islower(text[i])) {
                int position = text[i] - 97;
                int c = (position + key) % 26;
                cypher[i] = lowerAlphabet[c];
            } else if(isupper(text[i])) {
                int position = text[i] - 65;
                int c = (position + key) % 26;
                cypher[i] = upperAlphabet[c];
            }
        } else {
                cypher[i] = text[i];
        }
    }
    printf("ciphertext: %s\n", cypher);
}
Enter fullscreen mode Exit fullscreen mode

1) Criar uma array de caracteres.

O char cypher[strlen(text)] veio para fazer isso. Em C, temos que especificar o tamanho da array que vamos criar, como o tamanho pode ser variável, a depender de qual mensagem o usuário vai colocar, eu optei para que seja criado sempre com o mesmo tamanho da mensagem do usuário.

Dessa maneira, faz-se o uso do strlen() que faz parte da biblioteca string.h. Ela calcula o tamanho de uma string, e uma string é o que? Uma string é uma array de caracteres.
E então, seja qual foi o tamanho da string inicial, traduzirá para essa array de caracteres onde eu vou armazenar as letras criptografadas.

2) Uma string é um array de caracteres

Partindo desse pensamento, criei duas strings, uma para o abcdário minúsculo, e outro para maiúsculo. No enunciado, o problema levanta a ideia da letra A estar na posição 0, a letra B estar na posição 1, e por aí vai.

Então quando eu tenho:
lowerAlphabet[0] eu tenho acesso ao valor a
lowerAlphabet[1] eu tenho acesso ao valor b

Conseguindo assim replicar o enunciado do problema em questão.

3) Iterando e verificando se é uma letra do alfabeto

Começamos iterando sobre toda o tamanho da mensagem original.

for(int i = 0; i < strlen(text); i++) {
    //todo
}
Enter fullscreen mode Exit fullscreen mode

E agora usamos mais uma função, que a doc do cs50 fornece, isalpha() que pertence a biblioteca ctype.h. Dessa maneira, conseguiremos verificar posição-a-posição, se é um caracter alfabético ou não.

  • Se for, aí começa o processo de encriptar.
  • Se não, replica esses caracteres para a mensagem cifrada como são originalmente.

4) A lógica por trás e como ASCII é necessário

De novo, como no problema de readability, que já fiz uma explicação sobre, precisaremos da tabela de ASCII para descobrir a localização dos caracteres.

ASCII Chart

A lógica para letras maiúsculas é praticamente a mesma para a letras minúsculas, por isso falarei só das letras minúsculas.

Seguimos,

if(islower(text[i])) {
    //bloco de comandos
}
Enter fullscreen mode Exit fullscreen mode

Usamos a função islower(), da biblioteca ctype.h, em nossa condicional. Caso seja verdadeiro, executurá esse bloco de comandos

    int position = text[i] - 97;
    int c = (position + key) % 26;
    cypher[i] = lowerAlphabet[c];
Enter fullscreen mode Exit fullscreen mode

Vamos por partes agora, de acordo com a tabela ASCII a letra a corresponde ao valor 97.
Queremos que ela venha valer 0. Por quê?
Porque se ela valer 0, eu posso dizer que a letra a está na posição 0. Assim, para qualquer chave eu posso andar sobre a minha string lowerAlphabet e trocar o valor, assm ter a minha mensagem encriptada.

  • Então primeiro eu quero a posição:

int position = text[i] - 97;
Fazer uma subtração assim, vai forçar o C a transformar esse char na sua int correspondente

int position = 'a' - 97; --------------- char: a -> int: 97
int position = 0

E assim valerá para todos os caracteres que corresponderem ao abcedário de a a z.

  • Aplicar a fórmula da criptografia de acordo com o exercício proposto

int c = (position + key) % 26;

Pegamos a posição da letra da mensagem original e somamos com a quantidade de casas que vai pular, pegando assim o seu resto ao fazer a divisão por 26.

Então por exemplo:

- Letra a + key 1

  - Char: a => Int: 97
  - position = 97 - 97 => position = 0
  - c = (position + key) % 26 => c = (0 + 1) % 26 => c = 1
  - lowerAlphabet[1] = b

- Letra z + key 16

  - Char: z => Int: 122
  - position = 122 - 97 => position = 25
  - c = (position + key) % 26 => c = (25 + 16) % 26 => c = 15
  - lowerAlphabet[15] = p
Enter fullscreen mode Exit fullscreen mode
  • Armazenando esse valor em nossa array criptografada

cypher[i] = lowerAlphabet[c];

Seguindo a letra encontrada, armazena a nova letra na posição indicada.

E assim, ao terminar a iteração em toda a extensão da string da mensagem original, podemos imprimir a nova mensagem, agora criptograda atráves da nossa array cypher[] de chars.

Atráves da,
printf("ciphertext: %s\n", cypher);

E as letras maiúsculas?

Seguindo a mesma lógica acima, olhe a tabela ASCII e verifique, o que você mudaria?
Depois confira no código e repita os passos acima, a lógica é a mesma.

Não existe só uma maneira de resolver, nem a melhor. A melhor maneira, é aquela que você entende e onde você consegue resolver o problema da questão envolvida.

final image

Conclusão

Eu ia comentar sobre o exercício da substituição nesse mesmo post, mas vai ficar muito longo.

Ficará para uma parte 2.

Espero que este post tenha te ajudado a entender mais sobre essa manipulação de arrays, e como a biblioteca fornecida pelo docs do cs50 é importante.

Te vejo na próxima, e não se esqueça de me seguir no twitter.

Top comments (0)