I am trying to perform a Caesar cipher from text from user using modulo operation with the ascii characters. But, my code simply prints the entered test. For example, when the text entered is HELLO the program returns "HELLO". The goal is for a key of 13 it should print URYYB. Thank you.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int key = atoi(argv[1]);
string plaintext = get_string("Enter plaintext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
printf("%c", ((plaintext[i] + key) % 26) + 65);
}
else if (islower(plaintext[i]))
{
printf("%c", ((plaintext[i] + key) % 26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
}
printf("\n");
Preliminary analysis
Character code of 'H' is 72.
(72 + 13) % 26 + 65 = 85 % 26 + 65 = 7 + 65 ~ 'H'
Let's see if we subtract 65 first:
(72 - 65 + 13) % 26 + 65 = (7 + 13) % 26 + 65 = 20 % 26 + 65 = 20 + 65 = 85 ~ 'U'
Solution
printf("%c", ((plaintext[i] + key - 65) % 26) + 65);
and
printf("%c", ((plaintext[i] + key - 97) % 26) + 97);
respectively.
Proof
If you have a character code, C, where S <= C < S + 26, then the formula you used is:
((C + key) % 26) + S
however, the actual letter is L and we know that
C = S + L,
so the formula is
((S + L + key) % 26) + S
and, since
(A + B) % C = ((A % C) + (B % C)) % C,
replacing A with (S), B with (L + key) and C with 26, we get:
((S % 26) + ((L + key) % 26)) % 26, we see that the result is distorted by (S % 26), which, in the case of 65 is exactly 13. Since a distortion of 13 + the key of 13 you used in the modulo class of 26 will yield the initial letter!
So, the proposed new formula of
((C + key - S) % 26) + S = (((S + L) + key - S) % 26) + S = ((L + key) % 26) + S
is exactly what you need.
You are adding key to the value of each plaintext character, when it is meant to apply to the corresponding letter's index in the alphabet. For example, in case of the 'H' in ASCII, your formula is: (72 + 13) % 26 which gives 7 (which is also the index of H in the alphabet, when starting from zero).
You need to convert the (ASCII) value of the character to its index before applying key, e.g., ((plaintext[i] - 'A' + key) % (1 + 'Z' - 'A')) + 'A'.
The solution for 'H' would then become (72 - 65 + 13) % 26, which gives 20 (the correct answer, 7 + 13, the index of U).
Your cipher function just does nothing if the key is 13:
run a bit amended one and see the result :D
int main()
{
int key = 13;
char plaintext[] = "HELLO";
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
printf("%d, %d\n", (int)plaintext[i], (int)(((plaintext[i] + key) % 26) + 65));
}
else
{
if (islower(plaintext[i]))
{
//printf("%c", ((plaintext[i] + key) % 26) + 97);
}
else
{
//printf("%c", plaintext[i]);
}
}
}
}
printf("\n");
return 0;
}
Related
I first did this:
// Convert ASCII range down to a value from 0 to 25
char uppercase[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char lowercase[27] = "abcdefghijklmnopqrstuvwxyz";
char convertedUppercase[27];
char convertedLowercase[27];
for (int i = 0; i <= 26; i++)
{
convertedUppercase[i] = uppercase[i] - 'A';
convertedLowercase[i] = lowercase[i] - 'a';
}
// For each character in the plaintext: (DOESN'T WORK)
for (int i = 0, n = strlen(p); i <= n; i++)
{
// Rotate the character if it's a letter // ci = (pi + k) % 26
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
else if (islower(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
}
}
printf("ciphertext: %s\n", c);
but then I realized that the value of convertedUppercase will just be like 0 = NUL instead of 0 = A. Can anyone give me a hint what to do?
edit:
From the CS50 Discord:
"The caesar cipher formula (p + k) % 26 works on the premise that p (the plain text character) has a value of 0 - 25 (representing a - z or A - Z)
So if your plain char is 'x', that would have a value of 23, and if your key was 2, then the ciphered char would be:
(23 + 2) % 26
( 25 ) % 26
= 25 'z'
I'm kinda lost on how to do it.
This would be so much easier if you would provide a MRE.
I guess what you are observing is that you see a truncated cipertext if you attempt to output it via printf() with "%s".
This is however only because any "A" (that is a ciper A, i.e. after shifting by key) results in a 0 (which terminates string output, being the '\0' terminator) and most other letters result in unprintable characters.
This is because you only shift by key and map to 0-25 what needs to be the number representation (i.e. numeric instead of textual ciper) here:
c[i] = ((p[i]) + k) % 26;
In order to turn into textual cipher instead of numeric ciper, you need to do
convert textual to numeric, with -'A'
shift by key, with +k
map to 0-25, with %26
convert numeric to textual, with +'A'
I.e.
c[i] = ((p[i]-'A') + k) % 26 + 'A';
E.g. "H" from "Hello World".
textual to numeric, 'H' - 'A' -> 7
shift by key, 7 + 4 -> 11
map to 0-25, 11%26 -> 11
numeric to textual, 11 + 'A' -> 'L' is cipher
E.g. "W" from "Hello World".
textual to numeric, 'W' - 'A' -> 22
shift by key, 22 + 4 -> 26
map to 0-25, 26%26 -> 0
numeric to textual, 0 + 'A' -> 'A' is cipher
I am making a program that decrypts the vigenere cipher. User can only give alphabetical key.
for (int i = 0, counter = strlen(text); i < counter; i++)
{
// prints non-alphabetical characters straight away
if (!isalpha(text[i]))
{
printf("%c", text[i]);
}
else
{
// for index of key
index = meta % strlen(key);
if (islower(text[i]))
{
// separate cases depending upon case of key
if (islower(key[index]))
{
printf("%c", (((text[i] - 97) - (key[index] - 97)) % 26) + 97);
}
else
{
printf("%c", (((text[i] - 97) - (key[index] - 65)) % 26) + 97);
}
}
else
{
if (islower(key[index]))
{
printf("%d", (((text[i] - 65) - (key[index] - 97)) % 26) + 65);
}
else
{
printf("%c", (((text[i] - 65) - (key[index] - 65)) % 26) + 65);
}
}
// incrementing for next key alphabet
meta++;
}
Vigenere:
Input: MyName
key: qwerty
output: CuRrfc
De Vigenere:
Input: CuRrfc
key:qwerty
expected output: MyName
given output: 3_NaSK
How can I fix it?
The problem is the way the modulus operator deals with negative numbers.
For some characters you get negative values and the modulus operation then returns a negative value. You want a value in the range [0, 25].
You can fix it by adding 26 before taking the modulus.
printf("%c", (((text[i] - 97) - (key[index] - 97)) % 26) + 97);
would become
printf("%c", (((text[i] - 97) - (key[index] - 97) + 26) % 26) + 97);
Change all four rows the same way.
I cannot figure out why this thing doesn't scramble correctly. I read some other posts on this cipher and as far as I can tell I'm using the exact same algorithm as they are...
The areas commented out are tests I tried to make sure everything was passing through correctly. I believe it all goes through correctly then fails in the algorithm.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
string get_message(void);
string scramble(string key, string message);
int main(int argc, string argv[])
{
if(argc == 2)
{
string key;
string message;
key = argv[1];
//printf("KEY: %s<<",key);
message = get_message();
scramble(key, message);
}
else
{
printf("Please enter 2 arguments.\n");
return 1;
}
}
string get_message(void)
{
string message = "";
do
{
message = GetString();
}
while(strlen(message) < 1);
return message;
}
string scramble(string key,string message)
{
for(int i = 0, len = strlen(message), key_len = strlen(key); i < len; i++)
{
int letter = message[i];
//int Tkey = atoi(key[i % key_len]);
//printf("KEY: %d<<\n",Tkey);
if(islower(letter))
{
//printf("KEY(%d)",(key[i % key_len]-97));
letter = (((letter - 97) + (key[i % key_len])) % 26 + 97);
//printf("(%d)",(letter - 97) + (key[i % key_len])%26);
printf("%c",letter);
}
else if(isupper(letter))
{
//printf("(%d)", key[i]);
//printf("(%c)",letter); WE HAVE CORRECT LETTER
letter = (((letter - 65) + (key[i % key_len])) % 26 + 65);
printf("%c",letter);
}
}
printf("\n");
return 0;
}
I think your calculation is wrong:
You currently have
encryptedLetter = (letter - firstLetterOffset) + key[position % keyLength] % 26 + firstLetterOffset
by check the C operator precedence table we notice that % is evaluated before - or +, meaning that your code actually mean :
encryptedLetter = (letter - firstLetterOffset) + ( key[position % keyLength] % 26 ) + firstLetterOffset
Where you wanted :
encryptedLetter = ( (letter - firstLetterOffset) + key[position % keyLength] ) % 26 + firstLetterOffset
Conclusion : you need to put more parenthese to specify in which order you which to evaluate your expression.
In addition you took the letter number for the text character but not for the key !
Correct expression
encryptedLetter = ( (letter - firstLetterOffset) + key[position % keyLength] - firstLetterOffset ) % 26 + firstLetterOffset
Demonstration in javascript
This program is supposed to crypt a certain message with the vigenere cypher. The program is supposed to be 'case sensitive' both the message and the keyword. If the program encounters any special characters or numbers, is also supposed to print them untouched.
The last part seems to be working, and the rest, even though the math seems to be right, it doesn't print as it's supposed to. I'm also converting the ASCII values to A-Z/0-26, doing the cypher formula, and them converting them back to ASCII.
// key validation
string kw = argv[1];
int kwl = strlen(kw);
for (int i = 0; i < kwl; i++)
{
if (!isalpha(kw[i]))
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
}
// get message and length
string mssg;
mssg = GetString();
int lngth = strlen(mssg);
// cryptography
int k = 0;
for (int j = 0; j < lngth; j++)
{
if (isalpha(mssg[j]))
{
if (islower(mssg[j]))
{
if (islower(kw[k % kwl]))
printf("%c", (((mssg[j] - 97) + (kw[k % kwl] - 97)) & 26) + 97);
else
printf("%c", (((mssg[j] - 97) + (kw[k % kwl] - 65)) & 26) + 97);
k++;
}
else if (isupper(mssg[j]))
{
if (isupper(kw[k % kwl]))
printf("%c", (((mssg[j] - 65) + (kw[k % kwl] - 65)) & 26) + 65);
else
printf("%c", (((mssg[j] - 65) + (kw[k % kwl] - 97)) & 26) + 65);
k++;
}
}
else
printf("%c", mssg[j]);
}
printf("\n");
return 0;
}
I'm still getting an error somewhere on the math
The error is that you have & 26 instead of % 26.
I'm rather new to C and have recently been working on making a simple encryption/decryption program. I managed to get the encryption fine, but I've hit a road block with the decryption.
The relevant code is as follows:
Encryption (where asciinum is the ascii value for the letter, and k is the "vigenere" key to be shifted by).
//shifts lowercase letters by key
if (asciinum >= 97 && asciinum <= 123)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 97) + k;
asciinum = (asciinum % 26) + 97;
letterc = (char) asciinum;
//printf("%c\n", letterc);
cipher[j] = letterc;
p++;
}
//shifts uppercase letters by key
if (asciinum >= 65 && asciinum <= 91)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 65) + k;
asciinum = (asciinum % 26) + 65;
letterc = (char) asciinum;
cipher[j] = letterc;
p++;
}
I want to use a similar model to decrypt (using the same key), but the modulo method I used to wrap around the 26 characters doesn't work when asciinum is negative, as would be the case in subtracting a k of 5 from a (i.e. 0).
Decryption attempt...
//shifts uppercase letters by key
if (asciinum >= 65 && asciinum <= 91)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 65) - k;
asciinum = (asciinum % 26) + 65;
letterc = (char) asciinum;
cipher[j] = letterc;
p++;
}
Any help would be greatly appreciated. Thanks!
In pre-C99 C, the behaviour of % for negative numbers is implementation-defined. In C99 onwards, it's defined, but doesn't do what you want.
The easiest way out is to do:
((asciinum + 26) % 26)
Assuming asciinum can never get lower than -26.
Instead of using asciinum % 26, use (asciinum + 26) % 26, this will have you using modulus on positive numbers, at the cost of an extra addition each time through the cycle.