reverse engineer equation to convert ciphertext to plaintext - c

I have the following formula:
ciphertext[i] = ((plaintext[i] -'a' + k) % 26) + 'a';
I'm trying to solve for plaintext[i] given ciphertext[i].
I'm using a vigenere cipher. If I convert plain text to cipher text shouldn't there be a way to convert the cipher text back to plain text?
Here's the entire code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]){
if (argc !=2){
printf("FATAL ERROR: All hail Caesar!");
return 1;
}
for(int i = 0, n=strlen(argv[1]);i < n;i++){
if(!isupper(argv[1][i]) && !islower(argv[1][i])){
printf("FATAL ERROR: All hail Mark Anthony!");
return 1;
}
}
int cipherlength = strlen(argv[1]),ciphercount=0;
char cipherkey[strlen(argv[1])];
for(int i = 0, n=strlen(argv[1]);i < n;i++){
cipherkey[i] = argv[1][i];
}
string plaintext = NULL;
int k;
do{
printf("plaintext: ");
plaintext = get_string();
printf("ciphertext: ");
}while(plaintext == NULL);
char ciphertext[strlen(plaintext)];
char xiphertext[strlen(plaintext)];
k = atoi(argv[1]);
for (int i = 0,n=strlen(plaintext);i < n; i++){
int index = ciphercount % cipherlength;
if(isupper(cipherkey[index])) k = cipherkey[index] - 'A';
else if(islower(cipherkey[index])) k = cipherkey[index] - 'a';
if ((int)plaintext[i] >= 65 && (int)plaintext[i] <= 90){
ciphertext[i] = ((plaintext[i] -'A' + k) % 26) + 'A';
xiphertext[i] = ((plaintext[i] -'A' - k) % 26) + 'A';
ciphercount++;
}else if ((int)plaintext[i] >= 97 && (int)plaintext[i] <= 122){
ciphertext[i] = ((plaintext[i] -'a' + k) % 26) + 'a';
xiphertext[i] = ((plaintext[i] -'a' - k) % 26) + 'a';
ciphercount++;
}else {
ciphertext[i] = plaintext[i];
xiphertext[i] = plaintext[i];
}
printf("%c %c %c /n",plaintext[i],ciphertext[i],xiphertext[i]);
}
printf("\n");
}
When I enter abcdefghijklmnopqrstuvwxyz using random as the key word I get:
rbpgsrxhvmyxdnbsedjthykjpz as ciphertext[]
but when I enter rbpgsrxhvmyxdnbsedjthykjpz again using random as the key word I get:
abcdefghijklSnUpWXYt[v]^_z as xiphertext[]
so it works up to the letter m

You wouldn't be able to solve it, because % 26 operation produces the same values for different plaintext[i]s. You can produce one possible plaintext of a great number of possibilities by computing
plaintext[i] = ((ciphertext[i]-'a'- k) % 26) + 'a';
Demo.
thanks, I needed to add the following:
if ((plaintext[i] - 'a' - k)%26 < 0)xiphertext[i] = ((plaintext[i] -'a' - k + 26) % 26) + 'a';

Related

cs50 caesar - cypher not printing what is going wrong?

Stuck on this problem. Codes compiles, and takes input. however when attempting to use key '1' with plaintext 'a', i'm expecting 'b' but returning "\001" (which is not printing) when i check the debugger. Can someone help me explain why this is happening? I suspect error is when im allocating memory for the cypher test.. or when actually doing the cypher in my for / if statements.
int main(int argc,string argv[])
{
check_commands(argc);
//checks if key is alpha
string key = argv[1];
for (int i = 0; i < strlen(key); i++)
{
if (isalpha(key[i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//convert string argv[1] into an int
int k = atoi(key);
//ask user for pplaintect
string plaintext = get_string("Plaintext: ");
//create cyphertext variable
int s = strlen(plaintext);
char *cyphertext = malloc(s + 1);
printf("Cyphertext: ");
for (int i = 0; i < s; i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
// cypher based of k but keep upper
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
//print uppercase cypher
printf("%s", cyphertext);
}
if (islower(plaintext[i]))
{
//cypher based of k but keep lower
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
//print lowercase cypher
printf("%s", cyphertext);
}
}
else
{
printf("%c", plaintext[i]);
}
}
free(cyphertext);
printf("\n");
}
int check_commands(int argc)
{ //checks wether we have two command line arguments
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1; //error
}
return 0;
}
You're just putting the modulus into cyphertext. You need to add that to the first character of the alphabet to get the corresponding letter, just as you subtract the character before adding k.
cyphertext[i] = 'A' + ((plaintext[i] - 'A') + k) % 26;
Also, don't hard-code ASCII codes like 65 and 97. Use character literals.
You allocated an uninitialized memory
char *cyphertext = malloc(s + 1);
It does not contain a string. So you may not use the conversion specifier s in calls of printf like this
printf("%s", cyphertext);
Also in these statements
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
and
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
you are storing not printable alpha characters.
Also this record
int s = strlen(plaintext);
is redundant.
Use do-while loop instead of the for loop. For example
size_t i = 0;
do
{
if ( isupper( ( unsigned char )plaintext[i] ) )
{
// cypher based of k but keep upper
cyphertext[i] = 'A' + ( plaintext[i] - 'A' + k ) % 26;
}
else if ( islower( ( unsigned char )plaintext[i] ) )
{
//cypher based of k but keep lower
cyphertext[i] = 'a' + ( plaintext[i] - 'a' + k ) % 26;
}
else
{
cyphertext[i] = plaintext[i];
}
} while ( plaintext[i++] != '\0' );
puts( cyphertext );
free( cyphertext );

Cs50 Caesar Check50 fail

I am doing Caesar exercise from CS50 course, but it fail.
Here is the code:
# include <stdio.h>
# include <cs50.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv[1];
int l = strlen(key);
for (int i = 0; i < l; i++)
{
// if key[i] is an alphabet character
if (isalpha(key[i]) != 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//change charater to number
int k = atoi(argv[1]);
//print Plaintext
string plaintext = get_string("Plaintext: ");
int n = strlen(plaintext);
char ciphertext[n];
//declare plaintext in ASCII
int nplaintext[n];
//Change plaintext to ASCII
for (int i = 0; i < n; i++)
{
nplaintext[i] = (int)plaintext[i];
}
//Declare ASCII for ciphertext which we name "plusplaintext"
int plusnplaintext[n];
for (int i = 0; i < n; i++)
{
//if Capital
if ((nplaintext[i] < 91) && (nplaintext[i] > 64))
{
plusnplaintext[i] = 65 + ((nplaintext[i] + k) - 65) % 26 ;
}
//if Lowercase
else if ((nplaintext[i] < 123) && (nplaintext[i] > 96))
{
plusnplaintext[i] = 97 + ((nplaintext[i] + k) - 97) % 26 ;
}
//if not character a -> z and A -> Z
else
{
plusnplaintext[i] = nplaintext[i];
}
}
for (int i = 0; i < n; i++)
{
ciphertext[i] = (char)plusnplaintext[i];
}
printf("ciphertext: %s\n", ciphertext);
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
Here is the output from Check50:
:) caesar.c exists.
:) caesar.c compiles.
**:( encrypts "a" as "b" using 1 as key, output not valid ASCII text**
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
**:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key, output not valid ASCII text**
:) handles lack of argv[1]
When I test the code, sometimes it gives right result, sometimes it give the wrong result with some more characters at the end...
How can I correct my code?
The problem is with the logic here
//if Capital
plusnplaintext[i] = 65 + ((nplaintext[i] + k) - 65) % 26 ;
and
//if Lowercase
plusnplaintext[i] = 97 + ((nplaintext[i] + k) - 97) % 26 ;
use this logic instead
//if Capital
((((nplaintext[i] - 90) + 25) + key) % 26) + 65
//if Lowercase
((((nplaintext[i] - 122) + 25) + key) % 26) + 97
and it is also not necessary to assign the letters to a string, instead you can directly print it
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// Error Checking on the command line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else if (argc == 2)
{
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isdigit(argv[1][i]) == 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
int key = atoi(argv[1]);
string plain_text = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0; i < strlen(plain_text); i++)
{
if (isalpha(plain_text[i]) != 0)
{
// printf("%c", plain_text[i] + key);
if (isupper(plain_text[i]))
{
printf("%c", ((((plain_text[i] - 90) + 25) + key) % 26) + 65);
}
else
{
printf("%c", ((((plain_text[i] - 122) + 25) + key) % 26) + 97);
}
}
else
{
printf("%c", plain_text[i]);
}
}
printf("\n");
}
Instead of using the ascii value of a letter in your code, it could be helpful to keep them as characters for the sake of clarity. I took a snippet of your code and changed the values to demonstrate.
//if Capital
if ((nplaintext[i] <= 'Z') && (nplaintext[i] >= 'A'))
{
plusnplaintext[i] = 'A' + ((nplaintext[i] + k) - 'A') % 26 ;
}
This makes it clear what those values represent, and you don't have to reference an ascii chart. More comments would also help a user, or yourself later on, understand what the purpose is for each part of your code.
You could also create some functions outside of your main function. For example, to check for all digits in command line input, or change the letters by the amount given in the key. If you start working on long programs of code, it could be helpful to have functions defined that you can use as many times as you need. It also cleans up your main for clarity.
This function below takes the character of each letter in the original text (char p), then "moves" the character by k spaces (int k, given by the user as the key in the command line). It works when called in a for loop in main that iterates over each letter in the original given string (text[i]), with i being increased for each time the loop executes.
char rotate(char p, int k)
{
// declare variable for the rotated letter to be stored
char c;
// check if it is a letter
if (isalpha(p))
{
// check for lowercase letter
if (islower(p))
{
// subtract ascii value from p to initialize to 0 - 25 for computations
p -= 'a'; // if p is a, it is now initialized to 0, if b to 1, if c to 3, etc
c = (p + k) % 26; // use Caesar's algorithm to rotate letters, 'wrapping' by using % 26
c += 'a'; // add ascii value back to result to get the rotated letter
}
// the only other option is uppercase since we checked for only letters, do the same for uppercase letters as for lowercase
else
{
p -= 'A';
c = (p + k) % 26;
c += 'A';
}
}
// if it is the nul character '\0' return 0, do not print
else if (p == '\0')
{
return 0;
}
// if not a letter or nul character, return the character as is
else
{
c = p;
}
// print the rotated letter which is now stored in c
printf("%c", c);
// return the value of c
return c;
}

How to repeat characters in array

I am trying to implement Vigenere's Cipher in C but the problem is that when I try to repeat the key used in the array it is in, it breaks after the 4th letter. So if the key is ABC and the plaintext is HELLO, it returns HFNLO instead of HFNLP. When I look at my code it logically makes sense but it seems to just not work. Can anybody see the problem?
Here is the code:
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("usage: ./vigenere k\n");
return 1;
}
//asks for plain text
printf("plaintext: ");
string text = get_string();
string k = argv[1];
printf("ciphertext: ");
//checks to see if length of key is shorter than length of plaintext and duplicates it.
int count = 0;
while(strlen(k) <= strlen(text))
{
k[strlen(k + count)] = k[count];
count++;
}
//changes key to be within 0 - 25 and encrypts plaintext
for(int i = 0; i < strlen(text); i++)
{
if(k[i] >= 'A' && k[i] <= 'Z')
{
k[i] = k[i] - 65;
}
else if (k[i] >= 'a' && k[i] <= 'z')
{
k[i] = k[i] - 97;
}
//if statement for plaintext capital letters
if(text[i] >= 'A' && text[i] <= 'Z')
{
text[i] = text[i] - 64;
text[i] = ((text[i] + k[i]) % 26) + 64;
}
//if statement for plaintext lowercase letters
else if(text[i] >= 'a' && text[i] <= 'z')
{
text[i] = text[i] - 96;
text[i] = ((text[i] + k[i]) % 26) + 96;
}
//prints final cipher
printf("%c", text[i]);
}
printf("\n");
return 0;
}
You should use the modulo operator to compute the offset into the key.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <cs50.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("usage: ./vigenere k\n");
return 1;
}
string k = argv[1];
size_t klen = strlen(k);
if (klen == 0) {
fprintf(stderr, "vigenere: key must not be empty\n");
return 1;
}
printf("plaintext: ");
string text = get_string();
printf("ciphertext: ");
for (size_t i = 0; text[i] != '\0'; i++) {
int d = (unsigned char)k[i % klen];
if (d >= 'A' && d <= 'Z') {
d -= 'A';
} else
if (d >= 'a' && d <= 'z') {
d -= 'a';
} else {
d = 0;
}
int c = (unsigned char)text[i];
if (c >= 'A' && c <= 'Z') {
c = 'A' + (c - 'A' + d) % 26;
} else
if (c >= 'a' && c <= 'z') {
c = 'a' + (c - 'a' + d) % 26;
}
putchar(c);
}
putchar('\n');
return 0;
}

The Caesar cipher works only for uppercase letters (CS50)

My program works only for uppercase letters and I can't figure the problem out. Everything seems to be fine, but it actually isn't. This is a task from CS50 course (week2), by the way.
Here's my code:
#include <stdio.h>
#include "cs50.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{ /* Main should take only one parameter (except program execution, of course) */
if (argc != 2)
return 1;
string text = GetString(); // text to encrypt
int i, l = strlen(text);
int k = atoi(argv[1]); // shift value (key)
/* Shift value should be less or equal to 26 */
if (k > 26)
k = k % 26;
for (i = 0; i < l; i++)
{ /* Making sure the character to encrypt is a letter (from English alphabet) */
if ((islower(text[i])) || (isupper(text[i])))
{
if ((islower(text[i])) && ((text[i] + k) > 'z'))
text[i] = ('a' + text[i] + k - 'z' - 1);
if ((isupper(text[i])) && ((text[i] + k) > 'Z'))
text[i] = ('A' + text[i] + k - 'Z' - 1);
else
text[i] = text[i] + k;
}
printf("%c", text[i]);
}
printf("\n");
return 0;
}
Result
caesar.exe 13
HELLO WORLD hello world
URYYB JBEYQ uryyk sknyq
This whole block;
if ((islower(text[i])) || (isupper(text[i])))
{
if ((islower(text[i])) && ((text[i] + k) > 'z'))
text[i] = ('a' + text[i] + k - 'z' - 1);
if ((isupper(text[i])) && ((text[i] + k) > 'Z'))
text[i] = ('A' + text[i] + k - 'Z' - 1);
else
text[i] = text[i] + k;
}
Can be reduced to:
if (islower(text[i]) || isupper(text[i]))
{
int base = islower(text[i]) ? 'a' : 'A';
int ord = text[i] - base; // normalize text[i] to be between [0-25]
ord = (ord + k) % 26; // rotate
text[i] = base + ord; // convert back to alphabet value
}

Vigenere Cipher - Formula Explanation

First of all there is no one that I can ask this kind of question so please pardon me
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]) {
string key = argv[1];
int l = strlen(argv[1]);
if (argc != 2) {
return 0;
}
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha(key[i])) {
return 0;
}
key[i] = tolower(key[i]);
key[i] = key[i] - 97;
}
string txt = GetString();
for (int k = 0, p = strlen(txt); k < p; k++) {
if (isalpha(txt[k])) {
if (isupper(txt[k])) {
printf("%c", (((txt[k] - 65) + (key[k % l])) % 26 + 65));
}
if (islower(txt[k])) {
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
}
} else
if (!isalpha(txt[k])) {
printf("%c", txt[k]);
}
}
printf("\n");
return 0;
}
I can't quite get these 2 lines of code
key[i] = key[i] - 97;
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
Is there an easy explanation of why did we use the first and how the second one works?
The key used for the Vigenere cypher is supposed to be all letters. The first expression converts the string into an array of offsets, 0 for a, 1 for b, etc. 97 is the ASCII code for 'a'. It would be more readable to write:
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]);
key[i] = key[i] - 'a';
}
For the second expression, if the character txt[k] is a lower case letter, printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97)); computes and prints the transposed letter by adding the shift value (each character in key is used as a shift value one after the other, shifting by 0 for a, 1 for b etc.). Here are the steps:
The program computes the letter index txt[k] - 97, 97 being the ASCII code for 'a',
it then adds the shift value key[k % l], cycling the values in key in a circular fashion,
it takes the modulo 26 to get a letter index between 0 and 25.
it finally adds 97, the ASCII value of 'a' to convert the index back into a lowercase letter.
It would be less redundant and more readable to write it this way:
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % l]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % l]) % 26 + 'a';
}
putchar(c);
}
Also note that argv[1] should not be passed to strlen() before checking that enough arguments have been passed on the command line.
Here is a modified version of the program:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("missing key argument\n");
return 1;
}
string key = argv[1];
int klen = strlen(key);
if (klen == 0) {
printf("key cannot be empty\n");
return 1;
}
for (int i = 0; i < klen; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]) - 'a';
}
string txt = GetString();
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % klen]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % klen]) % 26 + 'a';
}
putchar(c);
}
putchar('\n');
return 0;
}
key[i] = key[i] - 97;
That line's use is to give key[i], which value represents the value of a caracter in ascii it's index in our alphabet. Then, 'a' will be given the value 0, 'b' the value 1 .... , and 'z' the value 25.
As for the second line,
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97))
it prints the caracter which's ascii value is
(((txt[k] - 97) + (key[k % l])) % 26 + 97))
The substraction of 97 has the same purpose as explained above.
The % 26 is the modulus, ie the remainder of ((txt[k] - 97) + (key[k % l])) when divided per 26 (integer division). Then, 97 is added again to convert the order, or index of the result into a corresponding ascii value.
This page might give you some more insight about the character representation in C.
As for the meaning of k,i and l, I let you grasp the inner functionning of the cypher by yourself, but the whole encryption happens in the second line you wished an explanation for.
PS : The parts with '65' are just the same, but with uppercase letters, since 'A' value in ascii is 65.

Resources