Vigenere Cipher In C not working [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am attempting to make the vigenere cipher.
Information about it is here: https://www.youtube.com/watch?v=9zASwVoshiM
My code doesnt seem to work for a few cases.
My code is listed below please dont send me a link how to make the vigenere cipher but instead a way to fix mine. If I put the key as z for example it is value 25 acc to alphabet. Now if I put the to be encrypted text as c which is 2 the new text is of value 27 and should show b but for me it doesn't. So if the value exceeds 25 it doesn't show what I want else it works. And for the actual output example:
ab as key should change ca to cb
#include<stdio.h>
#include<cs50.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
int main( int argc , string argv[]){
//string plaintext;
string key;
if(argc != 2){
printf("Please run the programme again this time using a command line argument!\n");
return 1;
}
key = argv[1];
int keys[strlen(key)];
for(int m = 0; m< strlen(key);m++){
if(isalpha(key[m])==false){
printf("Re-Run The programme without any symbols.\n");
return 1;
}
}
for(int b = 0; b < strlen(key);b++){
if(isupper(key[b]) == false){
keys[b] = key[b] - 'a';
}
else{
keys[b] = key[b] - 'A';
}
}
//printf("Enter a string which should be encrypted: \n");
string plaintext = GetString();
int plength = strlen(plaintext);
int klength = strlen(key);
string ciphertext = key;
for(int u = 0; u<plength;u++){
if(isalpha(plaintext[u])==false){
printf("%c",plaintext[u]);
continue;
}
int value = u % klength;
ciphertext[u] = (keys[value] + plaintext[u]);
//By the more than 90 I am referring to 'z'
if(ciphertext[u]>90){
ciphertext[u] = ciphertext[u] ;
}
printf("%c",ciphertext[u]);
}
printf("\n");
return 0;
}
Thanks
Kalyan

You are correctly processing the value in the key by consistently substracting from its code the code of 'A' for an uppercase letter and 'a' for a lower case one. It gives you: A|a => 0, B|b => 1, ... , Z|z => 25. Fine till here...
But when encrypting, you are just adding this value to the code of a character without wrapping at any time.
Let us use your example: key is 'z' => value 25 in keys, fine. Take character 'c'. Its ASCII(*) code is 0x63 or 99. 99+25=124 giving in ascii table '|' ! To correctly wrap it, you must ensure that in any way 'z' + 1 => 'a'. You code could be
/* test wrapping for lowercase letters */
if ((islower(plaintext[u]) && (ciphertext[u]>'z')) {
ciphertext[u] = ciphertext[u] - 'z' + 'a' - 1;
}
/* same for uppercase */
if ((isupper(plaintext[u]) && (ciphertext[u]>'Z')) {
ciphertext[u] = ciphertext[u] - 'Z' + 'A' - 1;
}
(*) the example assumed ASCII code because it is the most common nowadays, but the code only assumes that all uppercase letters are in sequence and all lowercase letters are also in sequence without any requirement for their exact values nor the order of upper and lower case sequences.

Related

CS50 Week 2 Caesar Practice

My code seems to be working properly except at the point when it should print the final output. The problem is to input a string and output an encrypted version. The encryption works by adding an int defined as the key and then adding that value to each character of the ascii values of the inputed string. My issue is that when the cypher text is outputted there are only spaces and no letters or even numbers.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[]) {
int key = atoi(argv[1]);
printf("%i\n", key);
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int cipher = text[i];
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
printf("%c", ciphermod);
}
printf("\n");
}
}
You've got a few issues going on here. Please make sure to thoroughly read the assignment before turning to others for assistance.
The assignment requires you to:
Only encode alphabetic characters. Look to the function isalpha() for this.
Encode both uppercase and lowercase characters accurately. Note that, in ASCII, uppercase letters and lowercase letters are separate entities.
Meaning, you must have your code be able to handle both, as they are each handled differently.
Perhaps taking some time to sit and take in the ASCII table may be helpful to you, as it will help you understand what is really happening when you add the key.
Use the correct formula for encoding letters. The i'th ciphered letter ci corresponding to the i'th plaintext letter pi is defined as ci = (pi + k) % 26.
Your code is equivalent to this formula, but it does not account for wrapping, uppercase/lowercase letters, etc. The project specification doesn't just ask you to repeat the formula, it asks you to solve a problem using it. To do so, you must understand it. I explain more, subsequently.
I recommend:
Modifying the text in-place. Currently, you calculate the ciphered text and print it. If you add code for modifying the text where it sits, it'll make ignoring non-alphabetic characters easier.
Modify the formula.
Where 𝚨 is the ASCII character code for the beginning of either the uppercase or lowercase characters, the formula might shake out as follows:
ci = (pi - 𝚨 + k) % 26 + 𝚨
What this modified formula does is first take the ASCII code for Pi and turn it into a number that represents which letter in the alphabet it is, ignoring case. Then, you can add the key(shift the cipher). Using % 26 on this result then makes sure that the result is between 1 and 26—always a letter. Finally, we add back 𝚨 so that the character has a case again.
Here's the modified code with the solution broken down, step by step:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) continue;
if (isupper(text[i])) {
// the letter's ASCII code on its own.
int charcode = text[i];
// the letter's index in the alphabet. A = 0, B = 1, etc.
// this is no longer a valid ASCII code.
int alphabet_index = charcode - 'A';
// the letter's index in the alphabet, shifted by the key.
// note, this may shift the letter past the end/beginning of the alphabet.
int shifted_alphabet_index = alphabet_index + key;
// the letter's index in the alphabet, shifted by the key, wrapped around.
// the modulo operator (%) returns the remainder of a division.
// in this instance, the result will always be between 0 and 25,
// meaning it will always be a valid index in the alphabet.
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
// this is the final ASCII code of the letter, after it has been shifted.
// we achieve this by adding back the 'A' offset so that the letter is
// within the range of the correct case of letters.
int final_shifted_charcode = shifted_index_within_alphabet + 'A';
text[i] = final_shifted_charcode;
}
else { // islower
int charcode = text[i];
int alphabet_index = charcode - 'a';
int shifted_alphabet_index = alphabet_index + key;
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
int final_shifted_charcode = shifted_index_within_alphabet + 'a';
text[i] = final_shifted_charcode;
}
}
printf("ciphertext: %s\n", text);
// ...
And here is the solution, simplified down:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) // if not alphabetic, skip
continue; //
if (isupper(text[i])) // if uppercase
text[i] = (text[i] - 'A' + key) % 26 + 'A'; //
else // if lowercase
text[i] = (text[i] - 'a' + key) % 26 + 'a'; //
}
printf("ciphertext: %s\n", text);
// ...
Just as a side note, the statement if (!isalpha(text[i])) is acting like something called a guard clause. This is a useful concept to know. Using guard clauses allows you to have simpler, more readable code. Imagine if I had nested all of the code inside the for loop under the if (isalpha(text[i])) condition. It would be harder to read and understand, and difficult to match up the different bracket pairs.
Edit: I would also echo what chqrlie said. Do not use argv[n] until you have verified that argc >= (n + 1)
The formula to compute the ciphered characters is incorrect:
you should only encode letters
you should subtract the code for the first letter 'a' or 'A'
you should add the code for the first letter 'a' or 'A' to the encoded index.
Note also that you should not use argv[1] until you have checked that enough arguments have been passed.
Here is a modified version:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
int key = atoi(argv[1]);
printf("%i\n", key);
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int c = text[i];
if (c >= 'a' && c <= 'z') {
int cipher = c - 'a';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'a' + ciphermod;
} else
if (c >= 'A' && c <= 'Z') {
int cipher = c - 'A';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'A' + ciphermod;
}
printf("%c", c);
}
printf("\n");
}
return 0;
}

While loops and arrays causing very odd behaviour...maybe a memory mixup

I'm tired of this tom-foolery occurring during runtime , although I'm sure we all are, when our programs screw up at runtime in the most obscure ways.
Getting to the point, the entire source code is a bit large to place here, but still <200 lines, so that's here . Use it if running the program, since the code I will post below is just functions, where I think the error lies.
Context : This is a sort of shift cipher with 8 different shifts taken using an 8 digit pin.
The issue is strange. Basically, the encrypt() function works correctly always -I've matched it by doing the algorithm for myself on paper ; for example, ABC is correctly encoded to 3c 45 46 -6f when the Pin is 12345678.
The strange issues are with the decrypt() function.
When the program is run for the first time, trying to run decrypt() on a valid ciphertext-pin pair always returns nothing except a /n (newline) . When tried with a different valid pin-ciphertext pair, after a successful run of encrypt() is done first, the decrypt() function just returns either the same message which was just encrypted or some other random output from the previously encoded message.
Without further ado, the legendarily screwed up decrypt function which I have rebuilt thrice now -
void decrypt()
{
printf("\n");
int *digits = pin(); int d[8];
getchar();
for (int i=0;i<8;i++)
d[i] = *(digits + i); //puts each digit in a local array.
printf("\nEnter encoded message -\n\n");
getchar();
int j; char ch, msg[3002];
for(int i=0; i < 3000;i++)
{
scanf("%x",&j);
if(j==-111){
msg[i] = '\0'; //terminates string with \0
break;
}
else{
if(ctln(i)==1)
ch = j - d[2];
else if(fib(i)==1)
ch = j + d[4];
else if(luc(i)==1)
ch = j - d[0];
else if(pent(i)==1)
ch = j + d[6];
else if(hex(i)==1)
ch = j - d[3];
else if(prm(i)==1)
ch = j + d[7];
else {
if(i%2 == 0)
ch = j - d[1];
else
ch = j + d[5];
msg[i] = ch;
}
}
}
printf("\nDecrypted message -\n\n");
puts(msg);
}
For context, as well as finding the culprits here, do make sure to read the full code here , with the pin() returning a pointer to a static int array holding all 8 digits , as well as the ctln() , fib(), luc(), pent(), hex(), prm() [ which check if position value i of char in message is a part of Catalan, Fibonacci , Lucas, Pentagon, Hexagon, Prime number series. More here.
Edit 1
I have already tried keeping different variable names, and some other things I can't fully recall. Also, because it is very relevant, below is the pin() function:
int *pin()
{
int num,q=0; static int pins[8];
printf("Enter 8-digit PIN : ");
scanf("%d", &num);
for(register int i = 10000000 ; i >= 1 ; i = (i/10)) // i is position of digit.
{
int d = ((num - (num % i)) / i); // d stores 'digit' ( divides quotient of (num % i) by i)
pins[q] = d; q++;
num = (num - ( d * i ));
}
return pins ; // pointer to static array storing digits of PIN
}
Edit 2
I had wrongly assigned pins[6] rather than pins[8] in the original code, I have corrected it but am still facing the same errors.
Edit 3
After correcting the mistake pointed out by MikeCAT, it now ignores the first character when deciphering.
Edit 4
The getchar() before scanf() was to blame, removing it fixes the last issue too. Thanks #MikeCAT !
In your decrypt() function, msg[i] = ch; is executed only if none of the functions ctln, fib, luc, pent, hex, prm returned 1.
Therefore, uninitialized value of non-static local variable msg, which is indeterminate, may be used for printing and undefined behavior may be invoked.
The part
msg[i] = ch;
}
should be
}
msg[i] = ch;
as it is done in encrypt() function.

What's wrong in my code ? (Vigenere cypher cs50, pset2)

My code for CS50 pset2 Vigenere cypher is as follows. I am new to C programming.
[ I edited the code once after I got some suggestions and this code(below) is my new edited code.]
When I run the code it produces infinite loop and also new encrypted text is not produced as it is supposed to be. Can I please get some suggestions and advice regarding the correction of my code ?
Thank you,
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2) //if it is not rqual to 2, it gives an error message.
{
printf("Enter the valid input : \n");
return 1;
}
if (argc == 2) //if two commands are given then it proceeds to other step.
{
string k = argv[1];
string m = GetString();
int l = strlen(k);
int p = strlen(m);
for( int i = 0; i <= p ; i++ ) //it has to keep on rotating from 0 to len of string and back to zero and so on.
{
{
i = i % l;
}
if (isalpha(m[i]) && isalpha(k[i])) // it proceeds ahead only if the input given is an alphabet, if the input is sth other than alphabet it prints exactly as it is.
{
for(int t = 0; t <= p ; t++)
{
if(isupper(m[t])) // when is it capital letter.
{
printf("%c", ( m[t] - 65 + k[i]) % 26 + 65);
}
if(islower(m[t])) // when it is small letter.
{
printf("%c" , ( m[t] - 97 + k[i])% 26 + 97);
}
}
}
else //if it is not an alphabet it returns as it is.
{
printf("%c", m[i]);
}
}
}
printf("\n");
return 0;
}
Let's look at the error. It says that the parameter you gave there is not an array, while you are using it as an array. And that's right : p is an integer, and not an array :
int p = strlen(msg);
Using p[i] means that you want to access the element number i of your p array. But it is impossible to reach this value, because p is simply an integer variable, and not an array.
What you probably wanted to use as an array was one of your string parameters, key or msg. A string variable in CS50 is the equivalent of a char * variable in classic C, and is used as an array of characters.

C beginner: Need explanation of error messages from "ideone"

I am attempting to write a program that accepts grammatically incorrect text (under 990 characters in length) as input, corrects it, and then returns the corrected text as output. I attempted to run the program using the online compiler, "ideone", but it returned quite a few errors that I don't quite understand. I have posted my code, as well as a picture of the errors below. Can anybody explain to me what exactly the errors mean?
#include "stdio.h"
char capitalize(int i); //prototype for capitalize method
int main(void)
{
char userInput[1200]; //Array of chars to store user input. Initialized to 1200 to negate the possibility of added characters filling up the array.
int i; //Used as a counter for the for loop below.
int j; //Used as a counter for the second for loop within the first for loop below.
int numArrayElements;
printf("Enter your paragraphs: ");
scanf("%c", &userInput); //%c used since chars are expected as input(?)
numArrayElements = sizeof(userInput) / sizeof(userInput[0]); //stores the number of elements in the array into numArrayElements.
if (userInput[0] >= 97 && userInput[0] <= 122) //Checks the char in index 0 to see if its ascii value is equal to that of a lowercase letter. If it is, it is capitalized.
userInput[0] = capitalize(userInput[0]);
//code used to correct input should go here.
for (i = 1; i < numArrayElements; i++) //i is set to 1 here because index 0 is taken care of by the if statement above this loop
{
if (userInput[i] == 32) //checks to see if the char at index i has the ascii value of a space.
if (userInput[i + 1] == 32 && userInput[i - 1] != 46) //checks the char at index i + 1 to see if it has the ascii value of a space, as well as the char at index i - 1 to see if it is any char other than a period. The latter condition is there to prevent a period from being added if one is already present.
{
for (j = numArrayElements - 1; j > (i - 1); j--) //If the three conditions above are satisfied, all characters in the array at location i and onwards are shifted one index to the right. A period is then placed within index i.
userInput[j + 1] = userInput[j];
userInput[i] = 46; //places a period into index i.
numArrayElements++; //increments numArrayElements to reflect the addition of a period to the array.
if (userInput[i + 3] >= 97 && userInput[i + 3] <= 122) //additionally, the char at index i + 3 is examined to see if it is capitalized or not.
userInput[i + 3] = capitalize(userInput[i + 3]);
}
}
printf("%c\n", userInput); //%c used since chars are being displayed as output.
return 0;
}
char capitalize(char c)
{
return (c - 32); //subtracting 32 from a lowercase char should result in it gaining the ascii value of its capitalized form.
}
Your code hase several problems, quite typical for a beginner. Teh answer to teh question in your last commenst lies in the way scanf() works: it takes everything between whitepsaces as a token, so it just ends after hey. I commented the code for the rest of the problems I found without being too nitpicky. The comments below this post might do it if they fell so.
#include "stdlib.h"
#include "stdio.h"
#include <string.h>
// Check for ASCII (spot-checks only).
// It will not work for encodings that are very close to ASCII but do not earn the
// idiomatic cigar for it but will fail for e.g.: EBCDIC
// (No check for '9' because non-consecutive digits are forbidden by the C-standard)
#if ('0' != 0x30) || ('a' != 0x61) || ('z' != 0x7a) || ('A' != 0x41) || ('Z' != 0x5a)
#error "Non-ASCII input encoding found, please change code below accordingly."
#endif
#define ARRAY_LENGTH 1200
// please put comments on top, not everyone has a 4k monitor
//prototype for capitalize method
char capitalize(char i);
int main(void)
{
//Array of chars to store user input.
// Initialized to 1200 to negate the possibility of
// added characters filling up the array.
// added one for the trailing NUL
char userInput[ARRAY_LENGTH + 1];
// No need to comment counters, some things can be considered obvious
// as are ints called "i", "j", "k" and so on.
int i, j;
int numArrayElements;
// for returns
int res;
printf("Enter your paragraphs: ");
// check returns. Always check returns!
// (there are exceptions if you know what you are doing
// or if failure is unlikely under normal circumstances (e.g.: printf()))
// scanf() will read everything that is not a newline up to 1200 characters
res = scanf("%1200[^\n]", userInput);
if (res != 1) {
fprintf(stderr, "Something went wrong with scanf() \n");
exit(EXIT_FAILURE);
}
// you have a string, so use strlen()
// numArrayElements = sizeof(userInput) / sizeof(userInput[0]);
// the return type of strlen() is size_t, hence the cast
numArrayElements = (int) strlen(userInput);
// Checks the char in index 0 to see if its ascii value is equal
// to that of a lowercase letter. If it is, it is capitalized.
// Do yourself a favor and use curly brackets even if you
// theoretically do not need them. The single exception being "else if"
// constructs where it looks more odd if you *do* place the curly bracket
// between "else" and "if"
// don't use the numerical value here, use the character itself
// Has the advantage that no comment is needed.
// But you still assume ASCII or at least an encoding where the characters
// are encoded in a consecutive, gap-less way
if (userInput[0] >= 'a' && userInput[0] <= 'z') {
userInput[0] = capitalize(userInput[0]);
}
// i is set to 1 here because index 0 is taken care of by the
// if statement above this loop
for (i = 1; i < numArrayElements; i++) {
// checks to see if the char at index i has the ascii value of a space.
if (userInput[i] == ' ') {
// checks the char at index i + 1 to see if it has the ascii
// value of a space, as well as the char at index i - 1 to see
// if it is any char other than a period. The latter condition
// is there to prevent a period from being added if one is already present.
if (userInput[i + 1] == ' ' && userInput[i - 1] != '.') {
// If the three conditions above are satisfied, all characters
// in the array at location i and onwards are shifted one index
// to the right. A period is then placed within index i.
// you need to include the NUL at the end, too
for (j = numArrayElements; j > (i - 1); j--) {
userInput[j + 1] = userInput[j];
}
//places a period into index i.
userInput[i] = '.';
// increments numArrayElements to reflect the addition
// of a period to the array.
// numArrayElements might be out of bounds afterwards, needs to be checked
numArrayElements++;
if (numArrayElements > ARRAY_LENGTH) {
fprintf(stderr, "numArrayElements %d out of bounds\n", numArrayElements);
exit(EXIT_FAILURE);
}
// additionally, the char at index i + 3 is examined to see
// if it is capitalized or not.
// The loop has the upper limit at numArrayElements
// i + 3 might be out of bounds, so check
if (i + 3 > ARRAY_LENGTH) {
fprintf(stderr, "(%d + 3) is out of bounds\n",i);
exit(EXIT_FAILURE);
}
if (userInput[i + 3] >= 97 && userInput[i + 3] <= 122) {
userInput[i + 3] = capitalize(userInput[i + 3]);
}
}
}
}
printf("%s\n", userInput);
return 0;
}
char capitalize(char c)
{
// subtracting 32 from a lowercase char should result
// in it gaining the ascii value of its capitalized form.
return (c - ' ');
}

Cipher text in C,How to repeat key characters

Explanation
The ciphertext is generated from the plaintext by “adding” corresponding characters of the plaintext and the key together. If the plaintext is shorter than the key, only some of the key will be used. Similarly, if the plaintext is shorter than the key, the key will be used multiple times.
For example, to encode the plaintext “HELLO” with the key “CAT”:
Plaintext: HELLO
Key: CATCA
Ciphertext: KFFOP
And to encode the plaintext “DOG” with the key “FIDO”:
Plaintext: DOG
Key: FID
Ciphertext: JXK
To add two letters together, use the following convention: A=1, B=2, …, Z=26. If the sum of two letters is greater than 26, subtract 26 from the sum. For example: A + E = 1 + 5 = 6 = F, and D + X = 4 + 24 = 28 = 2 = B.
Now the problem with my code is that i am unable to repeat the key characters for further coding of plain text if key characters are less,how to repeat the key characters,so further coding can possible?
Help me guys.
Here is my code:
#include<stdio.h>
#include<string.h>
int main()
{
char str[100],k[50],str1[100];
int i,n;
gets(str);// Input plain text.
gets(str1);//Input key.
for(i=0;str[i]!='\0';i++)
{
n=(str[i]-65+1)+(str1[i]-65+1);//Extracting the numerical position and adding them.
if(n>26) //if numerical value exceeds 26 then subtracting 26 from it and getting the numerical value.
{
n=n-26;
}
str[i]=n+64;//storing the ciphered character.
}
for(i=0;str[i]!='\0';i++)//printing the ciphered characters.
printf("%c",str[i]);
return 0;
}
You can use another loop variable an make the index of the key 0 every time it reaches its length. I have used variable j in this case. Try this code:
#include<stdio.h>
#include<string.h>
int main()
{
char str[100],k[50],str1[100];
int i,n;
gets(str);// Input plain text.
gets(str1);//Input key.
int lenk=strlen(str1),j; //calculate length of key
for(i=0,j=0;str[i]!='\0';i++,j++)
{
if(j==lenk) j=j-lenk; //make j=0
n=(str[i]-65+1)+(str1[j]-65+1); // add str1[j] instead
if(n>26)
{
n=n-26;
}
str[i]=n+64;//storing the ciphered character.
}
for(i=0;str[i]!='\0';i++)
printf("%c",str[i]);
return 0;
}
NOTE THAT THIS WORKS ONLY FOR CAPITAL LETTER, YOU HAVE TO CHANGE YOUR CODE FOR SMALL LETTERS
While writing the loop, the variable used to index the key should be reset to 0 in order to repeat the key (if original text length is larger).
for(int i = 0, j = 0; input[i] != '\0'; ++i, ++j) {
new_char = (input[i] - 64) + (key[j] - 64);
new_char = adjust(new_char);
cipher[i] = new_char + 64 ;
if(j == (key_length - 2)) // if j is at the end, excluding null character, then make j = -1, which gets incremented to j = 0 in the next loop iteration
j = -1;
}
Also use fgets for string input and dont use gets. Strings in C can be printed using the %s format specifier without writing an explicit loop to output the characters. For that make the last element of the cipher char array as the \0 character.
You could also use modular arithmetic to repeat the characters.
for(i=0;str[i]='\0';i++)
{
n = (str[i]-65+1 + (str1[i % lenk]-65 +1);
n = (n % 26) + 1;
str[i] = n+64;
//storing the ciphered character.
}
The expression i % 26 automatically rotates the value 0 through 25.
The same can be applied to rotate n from 1 to 26.

Resources