CS50 : S2 | Cifra de César - Parte 1
Matheus 🇧🇷
Posted on May 6, 2022
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);
}
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);
}
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
}
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.
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
}
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];
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
- 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.
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.
Posted on May 6, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.