Vigenere's cipher in C several problems - c

I have made program which encrypts and decrypts Vigenere's cipher but I have several problems.
Here is one: First letter of sentence is encrypted incorrectly.
Second one: After sentence I have letter K. I think that's because of space but I don't know how to fix it.
And third problem: There are no spaces in encrypted sentence I know ages ago when Vigenere's cipher was used there were no spaces but I would like to have groups of 5 letters if that's possible.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
char message[100];
int choice;
int i, j;
char pass[33];
int value;
char repeat = 1;
while (repeat == 1) {
printf("Enter operation\n");
printf("Encrypt - 1 \n");
printf("Decrypt - 2\n");
scanf("%d", &choice);
if (choice == 1) {
printf("Please enter message to encrypt\n");
while (getchar() != '\n');
fgets(message, 100, stdin);
printf("Enter password\n");
scanf("%s", &pass);
for (i = 0, j = 0; i < strlen(message); i++, j++) {
if (message[i] == ' ')
continue;
if (j >= strlen(pass)) {
j = 0;
}
if (!isupper(message[i])) {
value = (((message[i]) - 97) + ((pass[j]) - 97));
}
if (!islower(message[i])) {
value = (((message[i]) - 65) + ((pass[j]) - 65));
}
printf("%c", 97 + (value % 26));
}
printf("\nWould you like to repeat? [1/0]\n");
scanf("%d", &repeat);
} else
if (choice == 2) {
printf("Enter message do decrypt\n");
while (getchar() != '\n');
fgets(message, 100, stdin);
printf("Zadejte heslo\n");
scanf("%s", &pass);
for (i = 0, j = 0; i < strlen(message); i++, j++) {
if (message[i] == ' ')
continue;
if (j >= strlen(pass)) {
j = 0;
}
if (!isupper(message[i])) {
value = (((message[i]) - 96) - ((pass[j]) - 96));
}
if (!islower(message[i])) {
value = (((message[i]) - 64) - ((pass[j]) - 64));
}
if (value < 0) {
value = value * -1;
}
printf("%c", 97 + (value % 26));
}
printf("\nWould you like to repeat? [1/0]\n");
scanf("%d", &repeat);
}
}
return (EXIT_SUCCESS);
}
[

The main problem in your code is you apply the translation to characters with incorrect tests: you should translate uppercase letters is you have indeed an uppercase letter, not if you don't have a lowercase character. As coded, non letters are translated twice.
Change the code to:
if (islower((unsigned char)message[i])) {
value = (((message[i]) - 'a') + ((pass[j]) - 'a'));
}
if (isupper((unsigned char)message[i])) {
value = (((message[i]) - 'A') + ((pass[j]) - 'a'));
}
Also make sure you use character constants instead of hard-coded ASCII values and make the password lowercase.
In the deciphering case, the offsets seem incorrect. You should be using 'A' and 'a' too.

First things first, the message corruption. If you add a few printf() statements in the loop that is doing the encryption, you should be able to get an idea what is going wrong. You can always comment them out, or remove them altogether, anytime later.
That K on the end could be the encrypted \n that would have been read in with the message.
To display the encrypted message in groups of five characters, keep a count of how many characters you have actually displayed (make sure the instruction to increase the count is located where it will get skipped if the character is not displayed); and when this reaches 5, display a space and reset the counter to zero.

Related

The non-alphabetic problem in Vigenere problem set

I just have done with Vigenere problem in CS50, but still, there's one wrong only, the non-alphabetic characters, when you write in plaintext anything without spaces, comma, any non-alphabetic, the program will run well, but if you wrote any non-alphabetic character, like space, the next character will take the wrong key, this my code :
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
// Make sure there is a command-line argment
if (argc != 2)
{
printf("Error\n");
return 1;
}
// Variables
int key[strlen(argv[1])];
string plaintext;
// Make sure the comman-line argment is Alphabets then make the key
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (!isalpha(argv[1][i]))
{
printf("Error 2\n");
return 1;
}
if (islower(argv[1][i]))
{
key[i] = argv[1][i] - 'a';
}
else if (isupper(argv[1][i]))
{
key[i] = argv[1][i] - 'A';
}
}
// Ask the user to write the message
plaintext = get_string("plaintext: ");
printf("ciphertext: ");
// Make sure the plaintext doesn't equal NULL
if (plaintext != NULL)
{
for (int i = 0, n = strlen(plaintext); i < n ; i++)
{
// Print in slower case
if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] + key[i % strlen(argv[1])]) - 'a') % 26) + 'a');
}
// Print in upper case
else if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] + key[i % strlen(argv[1])]) - 'A') % 26) + 'A');
}
// Print the non alphabetic
else if (!isalpha(plaintext[i]))
{
printf("%c", plaintext[i]);
}
}
// Print a new line
printf("\n");
}
}
The problem is because you are using the same index for the plaintext and the key in this
for (int i = 0, n = strlen(plaintext); i < n ; i++) loop. The key will advance one position every time plaintext does. Obviously that is not what you want. You need to manage the key index independently of the plaintext index within that loop.
Suggest you rewatch the walkthrough and perhaps write out an example much the way Zamyla does the panda example. And it's never too soon to learn how to use debug50. If I recall correctly, there is a short for it in Week 2.
CS50x has a stack forum dedicated to questions and answers about CS50x and the psets.

CS50 Vigenere, code is almost done but I don't know what's missing?

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
string plaintext = get_string();
printf("ciphertext: ");
string key = argv[1];
for (int i = 0, t = 0, n = strlen(plaintext); i < n; i++, t++)
{
// if it's no letter, then:
if (!isalpha(plaintext[i]) && plaintext[i] != ' ')
{
printf("False");
return 1;
}
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1;
}
if (strlen(key) > number)
{
number = 0;
}
if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 65) + key[number]) % 26) + 65);
}
//if it is lowercase
else if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 97) + key[number]) % 26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
So there's something missing with my code. When I do ./vigenere baz and then type as plaintext: Hello, world!, I get ciphertext: ByffiFalse. I should be getting iekmo, vprke! Also, when I type ./vigenere hello, and then type bye as the plaintext, I get ciphertext bye too while it should be icp. Can someone figure out what's missing or wrong with my code?
The biggest two problems with your code are the calculating the correct key differential value (you're not), and key advancement. I'll talk about them in reverse order.
Key advancement should start with the first key character, then advance one by one with each plain text being processed. When the key position reaches end-of-string, it is restarted. The most basic pseudo code for that would be
char *keyp = argv[1];
for (loop through plainttext)
{
if (*keyp == 0) // reached the terminator ?
keyp = argv[1]; // then reset to beginning.
//... process the current plain text character, using *keyp
//... as the next key character to use.
// advance key to next position (possibly conditionally)
++keyp;
}
But your code doesn't do that. Rather, it advances the key immediately, meaning you're starting with the second character onward.
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1; // HERE. first pass will use key[1]. it should be key[0]
}
if (strlen(key) > number) // this is backward
{
number = 0;
}
Secondly, and probably more important, the whole point if a Vigenere cipher is effectively using a square shading table. See this link for a picture of that. The point of the algorithm you're coding is to act like that table exists using math. The offsets are the important part.When you do this calculation:
(((plaintext[i] - 65) + key[number]) % 26) + 65
which in reality should look like this:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
consider what that key character addition is doing. Take your example:
key: baz
plaintext: Hello, World!
The first ciphertext character by your calculation will be:
((('H' - 'A') + 'a') % 26) + 'A'
Note: the 'a' is there because your first-pass is broken by one, remember?
That crunches down as follows
(((7) + 97) % 26) + 'A'
((105) % 26) + 'A'
(1 % 26) + 'A'
1 + 'A'
'B'
And that's exactly what you're getting. But its wrong. Its wrong because this is wrong:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
^^^^^^^^^^^
That's the raw ascii value of the input character. What it should be is a calculated value between 1..26. In short, you're not adjusting your key input correctly.
Assumptive Solution
The following assumes the key will always be lower-case. It also fixes your first-skip logic, and decouples using cs50.h (which, frankly, I think does more harm than good). Finally it uses a `char* to track which key character is being used next. I leave the task of supporting mixed case input keys to you:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
char pt[256] = { 0 };
if (fgets(pt, sizeof pt, stdin))
{
// get the plaintext length
size_t ptlen = strlen(pt);
// remove trailing newline if present, and adjust ptlen
if (ptlen > 0 && pt[ptlen - 1] == '\n')
pt[--ptlen] = 0;
// the key we're using. intially at the start
char *key = argv[1];
for (size_t i = 0; i < ptlen; ++i)
{
// reset key if prior iteration landed on terminator
if (!*key)
key = argv[1];
if (isalpha((unsigned char)pt[i]))
{
if (isupper((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'A') + (*key-'a')) % 26) + 'A');
++key;
}
//if it is lowercase
else if (islower((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'a') + (*key-'a')) % 26) + 'a');
++key;
}
else
{
fputc(pt[i], stdout);
}
}
else
{
fputc(pt[i], stdout);
}
}
fputc('\n', stdout);
}
else
{
perror("Failed to read string");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Output from ./progname baz
plaintext: Hello, World!
Iekmo, Vprke!
All non-alpha characters (not spaces only) should be skipped without encoding. Do not print "False" and return on, for example ',' symbol in "Hello, world!" string. Also, you can encode string in-place. Thus, main loop may looks like
printf("plaintext: ");
string s = GetString();
if (s == NULL)
return 1;
for (int i = 0, len = strlen(s); i < len; ++i) {
if (isalpha(s[i])) {
/* encode s[i] in-place,
* all non-alpha characters left as is
*/
}
}
printf("ciphertext: %s\n", s);
Key characters should also be "shifted". For example, for uppercase letters
s[i] = ((s[i] - 'A') + (key[n] - 'A') % 26) + 'A';
if (++n >= keylen)
n = 0;
I suggest to normalize key before main loop, so that you will be able to use (key[n] - 'A') both for lower and upper characters from input string:
string key = argv[1];
strupper(k);
int keylen = strlen(key);
int n = 0;
Although I don't want provide full code because this is your courses, I think it would be better if you do it by yourself. But… some pieces:
strupper function:
void strupper(string s)
{
for (int i = 0, n = strlen(s); i < n; ++i)
s[i] = toupper(s[i]);
}
Compact main loop:
for (int i = 0, n = strlen(s); i < n; ++i) {
if (isalpha(s[i])) {
char ref = isupper(s[i]) ? 'A' : 'a';
int shift = k[j] - 'A';
s[i] = ref + (s[i] - ref + shift) % 26;
if (++j >= klen) j = 0;
}
}
p.s. You use the same key character for all input characters because of int number = 0; defined and zeroed inside for loop.

C language: there is a trailing character after the last character of my output

I am making a Caesar's Cipher for my lab sheet, and have made it able to encrypt 3 subtitution(Caesar's Cipher), which is the point of the exercise. But there has been one thing bugging me. First, there is a trailing character if i put it other than 3. For example, by typing "malware", and 2 for key.
This is my code :
#include<stdio.h>
#include<stdlib.h>
int main()
{
char text[100];
int key,i;
printf("Please enter a word/sentence (lowercaps) for encrypting :\n ");
fgets(text,100,stdin);
printf("Please enter the key that you desire : eg:14\n");
scanf("%d", &key);
for(i=0;i<strlen(text);i++)
{
if (key>=26)
{
key=key%26;
}
if (text[i]==' ')
{
continue;
}
if(text[i]+key>'z')
{
text[i]-=97;
text[i]+=26;
text[i]+=key;
text[i]%=26;
text[i]+=97;
}
else
{
text[i]=text[i]+key;
}
}
printf("this is your encrypted text : %s", text );
}
I hope I followed the correct indentation methods for coding. Got a lot of dislikes because of that
Code is 1) not properly detecting when a char is a lower case letter 2) encrypting non-letters including '\n' from fgets() which is causing OP's "trailing character after the last character of my output".
Instead:
if (text[i] >= 'a' && text[i]<= 'z') {
text[i] = (text[i] - 'a' + key)%26 + `a`;
}
else {
; // nothing
}
Alternatively
if (islower((unsigned char) text[i]) {
text[i] = (text[i] - 'a' + key)%26 + `a`;
}
Note: the above depends on char are encoded as ASCII.
A solution that does not depend on ASCII.
static const char lowercase[] = "abcdefghijklmnopqrstuvwxyz";
char *p = strchr(lowercase, text[i]);
if (p) {
int offset = (p - lowercase + key)%26;
text[i] = lowercase[offset];
}
I will simplify and correct this code to
#include <stdio.h>
int main() {
char text[100];
int key, i;
printf("Enter a word / sentence (lowercaps) for encrypting : ");
fgets(text, 100, stdin);
printf("Enter the key that you desire (eg. 14) : ");
scanf("%d", &key);
key %= 26; // Pull this out of the loop and remove the unnecessary if
for (i = 0; text[i]; ++i) { // Correct the loop condition
if (text[i] == ' ') continue;
if (text[i] + key > 'z')
text[i] = (text[i] - 97 + 26) % 26 + 97; // Simplify
else
text[i] += key;
}
printf("Encrypted text : %s\n", text);
return 0;
}
Input
Enter a word / sentence (lowercaps) for encrypting : malware
Enter the key that you desire (eg. 14) : 2
Output
Encrypted text : ocnyctg
As Blake_Lead said, this '\0' character was changed in your cypher
Indeed I was wrong about the length of the buffer as fgets() puts a '\0'
From the manual page:
A terminating null byte ('\0') is stored after the last character in the buffer.
So, you just need to change your test
if (text[i]==' ')
by something like:
if (text[i] < 'A' || text[i] > 'z' || (text[i] > 'Z' && text[i] < 'a') )

Caesar Cipher: Correct encryption but output missing spaces and punctuations

I have been working on this since yesterday and after much struggle have managed to encrypt the message successfully. However, my output is missing spaces.
As I understand it, the reason this is happening is because I'm using isalpha(), isupper() and islower() commands and as a result am ignoring the spaces in the original input.
Can one please help me with how to retain the original spaces and punctuation?
Below is my code- its far from elegant and any comments on style will also be appreciated!
(Also, while there are plenty of questions on Caesar Cipher, none barring one deal with this problem. Since this is my first week programming, I had trouble understanding the syntax in that one.)
There is a blatant mistake in my algorithm which causes it to output the wrong values if given certain arguments. For instance with a k of 13, inputting anything after the 13th alphabet (m, I think) will output something very bizarre.
I will amend this and get back soon! Till then, take my code with a grain of salt!
# include <cs50.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Please enter a valid number of arguments! \n");
return 1;
}
string num = argv[1];
int k = atoi(num);
if (k < 0)
{
printf("Please enter a valid number! \n");
return 1;
}
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
int oldletter = p[i];
int result1 = (oldletter + k);
int result2 = (oldletter - 65 + k);
int result3 = (result2) % 26;
int result4 = (oldletter - 97 + k);
int result5 = (result4) % 26;
if (isalpha(p[i]) && isupper(p[i]) && k < 26)
{
printf("%c", result1);
}
if (isalpha(p[i]) && isupper(p[i]) && k >= 26)
{
int result7 = (result3 + oldletter);
printf("%c", result7);
}
if (isalpha(p[i]) && islower(p[i]) && k < 26)
{
printf("%c", result1);
}
if (isalpha(p[i]) && islower(p[i]) && k >= 26)
{
int result8 = (result5 + oldletter);
printf("%c", result8);
}
}
printf("\n");
}
Corrected code, working properly: SPOILERS AHEAD
# include <cs50.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Please enter a valid number of arguments! \n");
return 1;
}
string num = argv[1];
int k = atoi(num);
if (k < 0)
{
printf("Please enter a valid number! \n");
return 1;
}
printf("Message: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
int oldletter = p[i];
int result1 = (oldletter - 65 + k);
int result2 = (result1) % 26;
int result3 = (oldletter - 97 + k);
int result4 = (result3) % 26;
if (isalpha(p[i]) && isupper(p[i]))
{
int result5 = (result2 + 65);
printf("%c", result5);
}
else if (isalpha(p[i]) && islower(p[i]))
{
int result6 = (result4 + 97);
printf("%c", result6);
}
else
{
printf("%c", p[i]);
}
}
printf("\n");
}
A common pitfall I see when people implement this is to go straight to ascii values. Consider making an alphabet array, you can just get the position of your current letter in it, and then determine what the modified letter should be.
Imagine adding a '%' character to this with the ascii solution, you'll end up having a ton of special if's. You can chose in that case to ignore spaces/etc if you like, personally I would add them to the alphabet array so the ciphertext didn't reveal the spaces (giving away hints).
You should probably chain together the if's as else if's, there is no need to evaluate an if condition if one of the previous was already true in your case. This would also allow for a final else case to be executed when isalpha is false like in the case with spaces.
Just change the if conditions to:
if (isalpha(p[i]) && isupper(p[i]) && k < 26)
{
printf("%c", result1);
}
else if (isalpha(p[i]) && isupper(p[i]) && k >= 26)
{
int result7 = (result3 + oldletter);
printf("%c", result7);
}
else if (isalpha(p[i]) && islower(p[i]) && k < 26)
{
printf("%c", result1);
}
else if (isalpha(p[i]) && islower(p[i]) && k >= 26)
{
int result8 = (result5 + oldletter);
printf("%c", result8);
}
else
{
printf("%c", p[i]);
}
I wanna note that your logic is pretty complex and you should also choose better names than the result* variables that you currently use, in programming readability and maintainability are really important. You can easily do assignments without considering them due to the small programs you write there but it's a good habit to get into.
I also took the course (with prior C experience) and uploaded my final solution for you to compare to/improve with once you finished yours. Just a warning, I used a function, not sure if it was already explained before this problem set but should be at least explained soon after. Here is my solution: http://pastebin.com/vJqPY6Ne

Array comparison and Loops In C

I am taking this free online course so resources and help are fairly limited. They want a Vigenere cipher. My code is passing all testing and I thought it was done until I typed "ho1W aRE y0Ou? as the text and "heLLo" as they key. The execution is perfect except for the lowercase u which does not continue through the 'z' - 'a' loop and instead prints ' ' '. The code does does the 'z' to 'a' loop successfully in the 'W' in "how" and 'y' in "you". The key, "heLLo" is does repeat successfully and is not at the end of the strlen when it hits the 'u'. It is also not increasing by 1 on non-alphabetical characters. I'm not sure where to go from this point. Can anyone please offer some suggestions? Thanks!
#include <cs50.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
// Function to get string (text) from user
string Encrypt(void);
int main(int argc, string argv[])
{
// Exits with improper arguement count
if (argc != 2)
{
printf("You must enter one keyword when running the program.\n");
return 1;
}
// Sets key entered for command argument 1
string key = argv[1];
// Checks key to make sure a-z is entered. Exits if not.
for (int i = 0, word = strlen(key); i < word; i++)
{
if (isalpha(key[i]))
{
}
else
{
printf("Only letters are allowed for the key.\n");
return 1;
}
}
string text = Encrypt();
// Secret used to print out final message
char secret = 'a';
// K contorls array place in key
int k = 0;
// If text is entered and alpha: compares text[i] and key[k]
if (text != NULL)
{
for (int i = 0, len = strlen(text); i < len; i++)
{
if (isalpha(text[i]))
{
// Checks k poition to make sure it is within array
if (k == strlen(key))
{
k = 0;
}
// Converts key if text is lowercase
if (islower(text[i]))
{
secret = (((text[i] - 'a') + (key[k] - 'a')) % 26) + 'a';
printf("%c", tolower(secret));
}
// Converts key if text is uppercase
if (isupper(text[i]))
{
secret = (((text[i] - 'A') + (key[k] - 'A')) % 26) + 'A';
printf("%c", toupper(secret));
}
k++;
}
// If not alpha ignores loop and prints text char.
else
{
printf("%c", text[i]);
}
}
}
return 0;
}
string Encrypt(void)
{
printf("Enter your text.");
string text = GetString();
return text;
}
The problem is when it gets to the 'u' in the string, you are on the 'L' in your key. So when this code runs:
secret = (((text[i] - 'a') + (key[k] - 'a')) % 26) + 'a';
By substitution you have:
secret = ((('u' - 'a') + ('L' - 'a')) % 26) + 'a';
Hint: 'L' - 'a' = -21. 'u' - 'a' = 20. Hope you can figure the rest out from here, good luck.

Resources