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.
Top comments (0)