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

mpfdev

Matheus 🇧🇷

Posted on May 6, 2022

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.

💖 💪 🙅 🚩
mpfdev
Matheus 🇧🇷

Posted on May 6, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

De uma página para vários components
javascript De uma página para vários components

November 28, 2024

Estruturas de Dados: Lista
datastructures Estruturas de Dados: Lista

November 27, 2024

Validação e Sanitização em Aplicações Web
braziliandevs Validação e Sanitização em Aplicações Web

November 26, 2024