I am helping a friend create a program that encrypts/decrypts messages using the "Vigenere Cipher." I was unsure what this was, so I did my own research and think I have it figured out.
My code runs fine from a syntax perspective. But, from a logic perspective, it does not work. From my understanding, when I encrypt a message with a key, if I decrypt the encrypted message using the same key, it should give me the original message. Mine does not. From my debugging attempts, I think the issue lies somewhere in my decrypting algorithm, but could be entirely wrong.
Here is my code:
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<string>
using namespace std;
int main(){
//initializing functions to be used
int giveInfo();
void encrypt(string message, string key);
void decrypt(string message, string key);
void newKey(string key);
string keyInput();
string messageInput();
int userChoice();
giveInfo();
//loop so that the user can decrypt/encrypt multiple messages
int counter = 1;
int userCounter;
while (counter == 1){
int choice = userChoice();
if(choice == 1){
string inputMessage = messageInput();
string inputKey = keyInput();
encrypt(inputMessage, inputKey);
}
else{
string inputMessage = messageInput();
string inputKey = keyInput();
decrypt(inputMessage, inputKey);
}
cout << "Would you like to decrypt/encrypt another message? (1 = yes, 2 = no)";
cin >> userCounter;
counter = userCounter;
system("CLS");
}
return 0;
}
//gives the user a basic description of cypher and what they need to input
int giveInfo(){
cout << "\nThe Vigenere Cypher is a polyalphabetic encryption/decryption method. It utilizes a 'key' (provided by the user, \nany word of any length) to determine which letters will replace others. This means in order to decrypt a message,\n one will need the key the person who encrypted the messafe used, ensuring a secure encryption. To use this program, \nyou will need to enter your message (this will be converted into all capitol letters) and a key which you would like to use. Do not use any spaces in your message.\n\n\n";
return 0;
}
string messageInput(){
//message place holder
string userMessage;
//asking for message
cout << "What is the message you would like to encrypt/decrypt?\n";
cin >> userMessage;
return userMessage;
}
string keyInput(){
//key place holder
string userKey;
//asking for key
cout << "What is the key you would like to use?\n";
cin >> userKey;
return userKey;
}
void decrypt(string message, string key){
//generating new key to match message length
int x = message.size();
for (int i = 0; ; i++)
{
if (x == i)
i = 0;
if (key.size() == message.size())
break;
key.push_back(key[i]);
}
string orig_text;
for (int i = 0 ; i < message.size(); i++)
{
// converting in range 0-25
int x = (message[i] - key[i] + 26) %26;
// convert into alphabets(ASCII)
x += 'A';
orig_text.push_back(x);
}
cout << "\n\nEncrypted Code: " + message+ "\n";
cout << "Key: " + key+ "\n";
cout << "Decrypted message: ";
cout << orig_text + "\n";
}
//takes user input (message to be encyrpted and key to be used) as arguments and returns encrypted
void encrypt(string message, string key){
string cipher_text;
//generating new key to match message length
int x = message.size();
for (int i = 0; ; i++)
{
if (x == i)
i = 0;
if (key.size() == message.size())
break;
key.push_back(key[i]);
}
for (int i = 0; i < message.size(); i++)
{
// converting in range 0-25
int x = (message[i] + key[i]) %26;
// convert into alphabets(ASCII)
x += 'A';
cipher_text.push_back(x);
}
cout << "\n\nOriginal message: " + message+ "\n";
cout << "Key: " + key+ "\n";
cout << "Encrypted message: ";
cout << cipher_text + "\n";
}
int userChoice(){
int choice;
cout << "Would you like to encrypt a message or decrypt a message? (1 =
encrypt, 2 = decrypt)\n";
cin >> choice;
return choice;
}
Any help?
Since your intention is to use an alphabet with a length of 26, you need to make sure your input is properly normalized prior to performing any encryption/decryption operations.
I would suggest ensuring that user input for the message & key is converted to upper case.
e.g. utilizing toupper: for(char &c : inputMessage) c = toupper(c)
Could you provide your input & output? Your code works just fine.
Original Message: ATTACKATDAWN
Key: LEMONLEMONLE
Encrypted Message: LXFOPVEFRNHR
Encrypted Code: LXFOPVEFRNHR
Key: LEMONLEMONLE
Decrypted Message: ATTACKATDAWN
Related
The Program should print the expected messages as expected but its not printing.
Plain Text message: Hello! how are you?
Expected encrypted message: Glqqv! bvc Rfl avm?
The program is printing: Glqqv!bvcRflavm
White spaces are totally ignored. How to fix it?
The Code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string alphabet {"!A2BCDEFGHIJ#KLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
string key {"!X2ZNLWEBGJHQDYVTK2F#UOMPCIASRxznlwebgjhqdyvtkfuompciasr"};
string secret_message{};
string encrypted_message{};
cout << "Enter your secret message: ";
getline(cin, secret_message);
cout << "'nEncrypting message.... ";
for (char c: secret_message)
{
float position = alphabet.find(c);
if(position != string::npos)
{
char new_char {key.at(position)};
encrypted_message += new_char;
}
}
cout << "\n Encrypted message is: "<< encrypted_message << '\n';
cout << "\n\n" << '\n';
return 0;
}
' ' is not part key.
To handle c not found in key and remain unchanged, add an else statement.
float position = alphabet.find(c);
if(position != string::npos) {
char new_char {key.at(position)};
encrypted_message += new_char;
} else // add
encrypted_message += c;
}
Recommend using type size_type as that is the type returned by .find() and used by .at().
// float position = alphabet.find(c);
std::string::size_type position = alphabet.find(c);
Float position = alphabet.find(c); //float is not making errors reading/printing the full line catch, but recommended you use an integer type instead.
Fix
size_t position = alphabet.find(c); //size_t fixed your issue an un-initialized int and You also forget to complete your if statement in the end by adding the function to set the position of encrypted_message to c as you assigned to be:
else
encrypted_message += c;
for (char c: secret_message)
{
size_t position = alphabet.find(c);
if(position != string::npos) {
char new_char {key.at(position)};
encrypted_message += new_char;
} else
encrypted_message += c;
}
I input a number in char type variable. like 12 or 22. but, console show me a 1 or 2.
How i get a whole number 12 ,22 in console?
#include <iostream>
int main()
{
using namespace std;
char a = 0;
cin >> a;
cout << a << endl;
return 0;
}
Here is console result.
12
1
C:\Users\kdwyh\source\repos\MyFirstProject\Debug\MyFirstProject.exe(프로세스 18464개)이(가) 종료되었습니다(코드: 0개).
이 창을 닫으려면 아무 키나 누르세요...
The reason I don't use int, string and something is because I want to get both number and Character in one variable.
So I want to see the results of combined numbers and character at the same time.
in that process i can't get a whole number.
#include <iostream>
using namespace std;
int index = 0;
constexpr int pagenum = 10;
void chapterlist(void);
void nextlist(void);
void beforelist(void);
void movechapter(char a);
int main(void)
{
char userin = 0;
bool toggle = 0;
cout << "결과를 볼 챕터를 고르시오." << endl;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cin >> userin;
if (userin == 'n')
{
backflash:
while(toggle == 0)
{
nextlist();
cin >> userin;
if (userin == 'b')
{
toggle = 1;
goto backflash;
}
else if (userin == 'n')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
while(toggle == 1)
{
beforelist();
cin >> userin;
if (userin == 'n')
{
toggle = 0;
goto backflash;
}
else if (userin == 'b')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
}
else
{
system("cls");
movechapter(userin);
}
return 0;
}
void chapterlist(void)
{
int x = 0;
for (x = index + 1; x <= index + 10; x++)
cout << "Chapter." << x << endl;
}
void nextlist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index + pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void beforelist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index - pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void movechapter(char a)
{
cout << "선택한 Chapter." << a << "의 결과입니다." << endl;
}
In movechapter(), console show me a is 1 or 2, not 12, 22.
First, you have to understand what achar type is.
Character types: They can represent a single character, such as 'A' or '$'. The most basic type is char, which is a one-byte character. Other types are also provided for wider characters.
To simplify that, char can only hold one character.
Where as with your code, "12" is actually 2 separate characters, '1' and '2', and that's the reason it would not work.
Instead of declaring a as a char type, you could declare it as an int type, which is a type designed to hold numbers. So you would have:
int a = 0;
However, do note that int often has a maximum value of 2^31.
Or you could use std::string to store character strings. However, do note that if you wish to do any calculations to your string type, you would need to convert them to a number type first:
int myInt = std::stoi(myString);
Edit:
So I have re-checked your code after your update, there is nothing wrong with using std::string in your case. You can still check if user have input n or b by:
if (userin == "n")
Note that you would use double quotation mark, or "letter", around the content that you want to check.
On the other hand, you could use:
if(std::all_of(userin .begin(), userin.end(), ::isdigit))
To check if user have input a number.
Although char is just a number, it's presumed to mean "single character" here for input. Fix this by asking for something else:
int a = 0;
You can always cast that to char as necessary, testing, of course, for overflow.
You should be reading characters into a string, and then converting that string into an int. It would also probably make more sense to use something like getline() to read input, rather than cin >> a.
#include <string>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
int main() {
std::string input_string;
/* note that there is no function that will convert an int string
to a char, only to an int. You can cast this to a char if needed,
or bounds check like I do */
int value;
while(1) {
getline(std::cin, input_string);
/* std::stoi throws std::invalid_argument when given a string
that doesn't start with a number */
try {
value = std::stoi(input_string);
} catch (std::invalid_argument) {
printf("Invalid number!\n");
continue;
}
/* You wanted a char, the max value of a `char` is 255. If
you are happy for any value, this check can be removed */
if (value > 255) {
printf("Too big, input a number between 0-255\n");
continue;
}
break;
}
printf("Number is %hhu\n", value);
}
As a homework exercise we were asked to use strchr to count the amount of times a single letter appears in a string of text. It needs to count upper or lower cases as equal. It was suggested we use some sort of bit operations.
I managed to get a working program.
But i would like to make the program more interactive by allowing me to use a cin to input the string instead of typing the string directly into the source code (Which was asked by the exercise).
Is it possible to do this? Or is it not possible in the way i wrote this code.
#include <iostream>
#include <cstring>
using namespace std;
int main(){
const char *C = "This is a necesarry test, needed for testing.";
char target = 'A';
const char *result = C;
const char *result2;
int count = 0;
int j[26] ={0};
//================================================================================================================================================
for(int i = 0; i <= 51; i++){
if (i == 26){
target = target + 6;
}
result2 = strchr(result, target);
while(result2 != NULL){
if (result2 != NULL){
result2 = strchr(result2+1, target);
if (i <= 25){
j[i] = j[i] +1;
}
if(i > 25){
j[i-26] = j[i-26] +1;
}
cout << target << "\t";
}
}
cout << target << endl;
target++;
}
char top = 'a';
for(int o = 0; o<= 25; o++){
cout << "________________________________\n";
cout << "|\t" << top << "\t|\t" << j[o] << "\t|" << endl;
top++;
}
cout << "________________________________\n";
}
Simply use getline() to get a string of characters from the console. Using getline you can also consider the spaces in the user input.
string input;
getline(cin, input);
Now to use this with the strchr functionn you simply have to convert this into a C Type string which can be done as follows :
input.c_str
This returns a C type string so you can put this as an arguement to the function,
You will need
#include <string>
#include <iostream>
#include <string.h>
#include <string>
#include <fstream>
using namespace std;
int get_ascii_int(char ch);
int get_offset_ascii(char ch2, int offset);
//int print_string_ints(string test_string);
int method3_substitution_abc();
//above are the function declarations
int main()
{
string test_string;//input of string
char ch = 0;//used in method1
char ch2 = 0;//used in method2
int index1 = 0;//used in for loop method1
int index2 = 0;//used in for loop method2
int offset = 0;//input of how much to offset
int new_ascii = 0;//the new ascii with offset
int ascii_value1 = 0;//the ascii value of the char
int option;//the menu choice of encryption method
int decision;//the decision to save or display
ofstream method1;//method 1 text file
ofstream method2;//method 2 text file
ofstream method3;//method 3 text file
string test_string_copy;//copy of string method 2
//Below is a description of the methods of encryption
cout << "There are three methods of encryption, listed below, to choose from: " << endl;
cout << "1. Converting characters into the corresponding ASCII values. " << endl;
cout << "2. Shifting characters right/left using the ASCII value of the characters ";
cout << "and a set offset amount. " << endl;
cout << "3. Using a reverse alphabet, so each letter will be replaced with the letter ";
cout << "on the opposite end of the alphabet. For example, A would become Z. " << endl;
cout << "Which encryption method would you like to use, 1, 2, 3? ";
cin >> option;
switch (option)
{
case '1':
method1.open("method1.txt");
cout << "Input a word or name: ";
getline(cin, test_string);
for (; index1 < test_string.size(); index1++);
{
ascii_value1 = get_ascii_int(test_string[index1]);
}
cout << "Would you like to display the file or save it, enter 1 for display or 2 for save?";
cin >> decision;
if (decision == '1')
{
cout << "The encrypted code is " << ascii_value1 << endl;
}
else
{
if (method1.is_open())
{
method1 << "The encrpyted code is " << ascii_value1 << endl;
method1.close();
}
else
cout << "Unable to open file." << endl;
}
break;
case '2':
method2.open("method2.txt");
cout << "Input a word or name: ";
getline(cin, test_string);
test_string_copy = test_string;
for (; index2 < test_string_copy.size(); index2++);
{
new_ascii = get_offset_ascii(test_string_copy[index2], ch2);
}
cout << "Would you like to display the file or save it, enter 1 for display or 2 for save?";
cin >> decision;
if (decision == '1')
{
cout << "The encrypted code is " << new_ascii << endl;
}
else
{
if (method2.is_open())
{
method2 << "The encrypted code is " << new_ascii << endl;
method2.close();
}
else
cout << "Unable to open file." << endl;
}
break;
case '3':
method3.open("method3.txt");
method3_substitution_abc();
break;
}
return 0;
}
//listed below are the function definitions
int get_ascii_int(char ch)
{
return ((int)ch);
}
int get_offset_ascii(char ch2, int offset)
{
int new_offset_value;//the value after adding the determined offset to the ascii value of the letter
new_offset_value = (int)ch2 + offset;
(char)new_offset_value;
return (new_offset_value);
}
//int print_string_ints(string test_string)
//{
//for (int i = 0; i < test_string.size(); i++)
//{
//(int)test_string[i++];
//}
//return 0;
//}
int method3_substitution_abc()
{
char test_string[100];
cout << "Enter a name or phrase: ";
cin >> test_string;
if (isupper((int)test_string))
{
int stalpha = 65;//start of alphabet
int endalpha = 90;//end of alphabet
char b[100];//array to reverse the alphabet
for (int i = 0; test_string[i] != '\0'; i++)
{
b[i] = endalpha - (test_string[i] - 65);
}
}
else if (islower((int)test_string))
int stalpha = 97;//start of alphabet
int endalpha = 122;//end of alphabet
char b[100];//array to reverse the alphabet
for (int i = 0; test_string[i] != '\0'; i++)
{
b[i] = endalpha - (test_string[i] - 97);
}
return 0;
}
I am trying to write this encryption program. And I am just getting really confused on why it won't run.
For example the switch statement is not running correctly, it will go to the correct case and then skip the input of the string?
This is my first experience with C++ so I struggle to debug.
I am having issues with saving the file to a text file after the user chooses to save or display? It has to be done after every case in the switch statement.
I also know the for loops I am using are not correct for method 1 and 2? Could someone check those out and tell me what the issue is. I am pretty sure it has to do with the parameters for the for loop.
And I don't know if I should use a string or an array for this? (In the part where the user inputs a string
At least the first problem you've identified (with the switch statement) is pretty simple and clear.
You've defined option as an int, so when you read it it's read as an integer. That means if the user enters 1, it'll have the value 1, which is different from the value '1'. '1' is a character that will (for example) print as 1, but its value is actually 49 in most character sets.
You have two obvious choices: either change option to be a char, so it'll be read as a character instead of an integer, or else change the values in the switch statement from '1', '2', etc., to just 1, 2, etc.
At a guess, the problem you're seeing from getline is a fairly common one when you mix a string extractor (e.g., cin >> my_string;) with std::getline. The string extractor extracts a string from the stream, but leaves the new-line character in the stream buffer. Then when you call std::getline, it reads that new-line as an empty string, so it doesn't wait for you to enter more input.
If you really have to mix the two this way, you probably want to add a call to std::cin.ignore to read and ignore any data up to and including the new-line character. Then when you call std::getline, it'll actually read some data.
I'm currently attempting to implement a substitution cipher that for some reason keeps crashing, the code is fairly straight forward but I keep running into problems I believe originate in the for loop or when I attempt to read in the data from a file.
cout << "Ener a key :";
cin >> key;
cin.ignore();
cout << endl << "Enter input file name: ";
getline(cin,fileIn);
inputfile.open(fileIn.c_str(), ios::in);
cout << endl << "Enter output file name: ";
getline(cin,fileOut);
outfile.open(fileOut.c_str(), ios::app);
cout << endl << "[E]ncryption or [D]ecryption? :";
cin >> EorD;
//Encryption
if (EorD == "E" || "e")
{
while(!inputfile.eof()) // Reading in file data, while not end of file.
{
getline(inputfile,plainText);
}
for (int i = 0; i <= plainText.length(); i++)
{
char letter = plainText.at(i);
int val = (int)letter; // getting ascii value of each letter.
int EnVal = (val - 32) + key;
if(EnVal > 95)
{
EnVal = (EnVal - 95) + 32;
}
char EnLetter = static_cast<char>(EnVal);
outfile << EnLetter;
change
for (int i = 0; i <= plainText.length(); i++)
to
for (int i = 0; i <= plainText.length()-1; i++)
because out of range. Even better use iterator.
also change this:
if (EorD == "E" || "e")
to
if (EorD == "E" || EorD == "e")
because former is always true.
as James Kanze pointed out, don't use std::string::at, you don't need it here, change it to std::string operator[] and my advice: additionally cover your code in a nice try{}catch(...){} block
you might consider something like this:
#include <vector>
#include <iterator>
#include <algorithm>
int key=100;
char op(char c){
char letter = c;
int val = (int)letter; // getting ascii value of each letter.
int EnVal = (val - 32) + key;
if(EnVal > 95)
{
EnVal = (EnVal - 95) + 32;
}
char EnLetter = static_cast<char>(EnVal);
return EnLetter;
}
int main(){
try{
std::string s="piotrek";
std::vector<char> vc_in(s.begin(),s.end());
std::vector<char> vc_out;
std::transform (vc_in.begin(), vc_in.end(),
std::back_inserter(vc_out), op); //this do the thing
std::copy(vc_out.begin(), vc_out.end(),
std::ostream_iterator<char> (std::cout,"_")); // to print
}catch(std::exception& e){
cout<<"exception: "<<e.what();
}
return OK;
}
You are looping one index too far in the plainText string. Since it has length() entries and the first one is 0, the last index is length()-1. Try this:
for (int i = 0; i < plainText.length(); i++)
Otherwise plainText.at(i) will crash when i is too big.