How to access variable from class array object in function? - c++

I am creating a Meet In The Middle cryptanalysis way to find the keys for a double caesar cipher.
I created a class Table where it holds each 26 possibilites of the cipher text along with the associated key used to get the cipher text.
Next I have a function findKeyPair that takes the second encrypted plain text and decrypts testing each key and searches the class table array object I made for matching cipher text. If there is a match the findKeyPair function sets a 2 element array keySolutions with the first element being the first key and the second element being the second key.
Then it should display the 2 keys used in the double caesar cipher.
The problem I am having is in the findKeyPair function. Whenever I use my getText() and getKey() function in findKeyPair the data returned seems blank. I have tried passing the point and by reference, but it is already an array so I don't understand where the problem is coming from.
This is my project so far, so if you want to run it you can:
`
#include <iostream>
#include <string>
#include <bits/stdc++.h>
using namespace std;
class Table {
private:
string cipherText;
int key_l;
public:
Table() : cipherText(""), key_l(0) {}
void putEntry(string plainText, int key);
string getText();
int getKey();
void printEntry();
};
string caesarCipher(string plainText, int key);
void findKeyPair(Table table[], string cipherText, int keySolutions[]);
int main()
{
Table table[26];
int keySolutions[2] = {0,0};
string knownPlainText = "Hello World";
int key1 = 4; int key2 = 13;
string cipherText = caesarCipher(knownPlainText, key1);
cipherText = caesarCipher(cipherText, key2);
findKeyPair(table, cipherText, keySolutions);
cout << "Key 1 = " << keySolutions[0] << "\nKey 2 = " << keySolutions[1] << endl;
return 0;
}
string caesarCipher(string plainText, int key)
{
string result = "";
for (int i = 0; i < plainText.length(); i++) {
if (plainText[i] == 32)
result += char(plainText[i]);
else if (isupper(plainText[i]))
result += char(int(plainText[i] + key - 65) % 26 + 65);
else
result += char(int(plainText[i] + key - 97) % 26 + 97);
}
return result;
}
void findKeyPair(Table table[], string cipherText, int keySolutions[])
{
string middleText = "";
string temp = "";
int key = 0;
for (int i = 0; i < 26; i++)
{
key = 26 - i;
middleText = caesarCipher(cipherText, key);
for (int j = 0; j < 26; j++)
{
temp = table[j].getText();
if (middleText.compare(temp) == 0)
{
keySolutions[0] = table[j].getKey();
keySolutions[1] = key;
}
}
}
}
void Table::putEntry(string plainText, int key)
{
cipherText = caesarCipher(plainText, key);
key_l = key;
}
string Table::getText()
{
return cipherText;
}
int Table::getKey()
{
return key_l;
}
void Table::printEntry()
{
cout << cipherText << endl;
}
`
I have tryed passing the Table table object array to the findKeyPair function by reference and the pointer. But no matter what the findKeyPair function can't access cipherText from the class Table when I use getText() function.

Related

Encrypting a String in C++

I am in desperate need of help with my C++ program that is supposed to encrypt a string that the user inputs (source) and saves the encrypted string to another string (destination).
Before the string is encrypted, it runs through the lowerCaseString() function where it converts source to all lowercase. This function works perfectly fine.
Can you help my make my program properly display the encrypted message? I am new to C++.
My error:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 0) >= this->size() (which is 0)
#include <iostream>
#include <string>
#include <ostream>
#include <fstream>
#include <sstream>
#include <cctype>
#include <vector>
using namespace std;
string lowerCaseString(string &source);
bool substitution(string &source, string cipherKey, string &destination);
int main()
{
string source;
string cipherKey = "qwertyuiopasdfghjklzxcvbnm";
string destination;
ifstream inFile;
cout << "Please enter a string: " << endl;
cin >> source;
//eventually has to write to a file, but I want to get the cipher part working first
//cin >> cipherKey;
// inFile.open("C:/Users/ellio/OneDrive/Desktop/Freshman Semester 2/ECE 1080C/ECE Labs/otherlabfiles/small-file.txt"); /*make necessary change for
// file access path*/
// if (!inFile){
// cout << "Input file cannot be opened" << endl;
// return 0;
// }
// stringstream buffer;
// buffer << inFile.rdbuf();
// //change to file_string
// source = buffer.str();
lowerCaseString(source);
substitution(source, cipherKey, destination);
cout << destination << endl;
return 0;
}
//converts all letters that are upper case to lower case in source
string lowerCaseString(string &source)
{
unsigned i;
for(i = 0; i < source.size(); ++i)
{
if(isupper(source.at(i)))
{
source.at(i) = tolower(source.at(i));
}
}
return source;
}
//encrypts the source string based on the cipher key, then writes the encrypted string to string destination
bool substitution(string & source, string cipherKey, string &destination)
{
//the boolean function type is irrelevant to my error (I tried to run it with void type), I just have to return true or false if the
//string source is empty
//alphabet is used to compare to each value in source
string alphabet = "abcdefghijklmnopqrstuvwxyz";
unsigned i;
unsigned j;
//this for loop is probably unnecessary but I did it for the purpose of potential debugging
for(i = 0; i < source.size(); ++i)
{
destination.at(i) = source.at(i);
}
//if the string is empty
if(source.size() == 0)
{
return 0;
}
//if the string isn't empty
else
{
for(i = 0; i < source.size(); ++i)
{
for(j = 0; alphabet.at(j) == 'z'; ++j)
{
//if the current character in source is equal to a certain letter in the
//alphabet, write the corresponding value from the cipher key into destination
if(source.at(i) == alphabet.at(j))
{
destination.at(i) = cipherKey.at(j);
}
}
}
//changed this maybe change back
return 1;
}
}
Here is your substitution method working. The destination string was empty, causing the error :
bool substitution(string & source, string cipherKey, string &destination)
{
string alphabet = "abcdefghijklmnopqrstuvwxyz";
destination = source; // To make sure the size of destination is the same as source
if(source.size() == 0)
{
return false;
}
else
{
for(unsigned int i = 0; i < source.size(); ++i) // You can declare i and j in the loop if you want (in c++ not in c)
{
for(unsigned int j = 0; j < alphabet.size(); ++j) // way easier to use size instead of finding 'z'
{
if(source.at(i) == alphabet.at(j))
{
destination.at(i) = cipherKey.at(j);
}
}
}
return true;
}
}
Note that the character finding bit can be reduced to :
bool substitution(string & source, string cipherKey, string &destination)
{
string alphabet = "abcdefghijklmnopqrstuvwxyz";
destination = source; // To make sure the size of destination is the same as source
if(source.size() == 0)
return false;
else
{
for(unsigned int i = 0; i < source.size(); ++i)
destination.at(i) = cipherKey.at(alphabet.find(source.at(i)));
return true;
}
}
You were trying to access destination but it was empty. Try to avoid operating on particular indexes. It could be done like this:
void substituteCharacters(const std::string& source,
const std::string& cipherKey,
std::string& destination)
{
destination.reserve(source.size());//allocate memory once, so no allocation during push_backs
for(auto c : source)
destination.push_back(cipherKey[c-'a']);
}

Making a Caesar Cypher, and it does not want to decipher the message

For a project, we have to make a Caesar Cipher using classes and save the encrypted message inside of a file so a user can decipher it with the program.
I input the message and it has no problem encrypting the message according to the displacement/key I input (since I gave an option for the user to place the displacement they please).
However, the problem lies in decripting the message. It seems to only decript the penultimate or last letter of what I inputted and it doesnt even bother to show the remaining characters of the message.
I have currently no idea why its acting the way it is, I figured I would have to change the message to take char variables instead of string, but that would mean rewriting a large chunk of the code, and at the moment, I would like to avoid having to rewrite the code from scratch. If there are no other options, then I guess I will have to rewrite the code.
Here is the code, (hope that helps and sorry if my message may seem messy, this is the first time I post anything here):
#include<iostream>
#include<string>
#include<fstream>
#include<ctime>
#include<cstdlib>
/* This is a program that will grab a message from the user and encrypt it, then decrypt it
It will also generate a random 8-digit character password used to access the encrypted file
It will also have the ability to allow the user to choose how many spaces the cipher will take into account */
using namespace std;
//Implement a set displacement and get displacement
class Cipherer
{
private:
int displacement;
string message;
//string decryptMessage;
public:
void setDisplacer(int key);
int getDisplacer()const;
void msgEncripter(string, int);
string getMessage()const;
void msgDecripter(string);
string getDecription()const;
};
void Cipherer::setDisplacer(int key)
{
displacement = key;
}
int Cipherer::getDisplacer()const
{
return displacement;
}
void Cipherer::msgEncripter(string msg, int key)
{
string encriptedMsg = msg;
//.size returns the number of elements
for (unsigned int i = 0; i < msg.size(); i++)
{
if (msg[i] == 32) //32 is the value in ASCII of the space character
{
continue;
}
else
{
if ((msg[i] + key) > 122)
{
int temp = (msg[i] + key) - 122;
encriptedMsg[i] = 96 + temp;
}
else if (msg[i] + key > 90 && msg[i] <= 96)
{
int temp = (msg[i] + key) - 90;
encriptedMsg[i] = 64 + temp;
}
else
{
encriptedMsg[i] += key;
}
}
}
message = encriptedMsg;
}
string Cipherer::getMessage()const
{
return message;
}
void Cipherer::msgDecripter(string msg)
{
string decriptedMsg;
for (unsigned int i = 0; i < msg.size(); i++)
{
if (msg[i] == 32)
{
continue;
}
else
{
if ((msg[i] - displacement) < 97 && (msg[i] - displacement) > 90)
{
decriptedMsg[i] = (msg[i] - displacement) + 26;
}
else if ((msg[i] - displacement) < 65)
{
decriptedMsg[i] = (msg[i] - displacement) + 26;
}
else
{
decriptedMsg = msg[i] - displacement;
}
}
}
message = decriptedMsg;
}
string Cipherer::getDecription()const
{
return message;
}
static const char PASSWORD_POOL[] =
"0123456789";
int poolSize = sizeof(PASSWORD_POOL) - 1;
char getRandChar()
{
return PASSWORD_POOL[rand() % poolSize];
}
int main()
{
srand(time(0));
string pass, input, msg;
int key;
Cipherer message;
ofstream outputFile;
ifstream inputFile;
outputFile.open("SecretMSG.txt");
cout << "Write a message: \n";
getline(cin, msg);
cout << "Choose the displacement of the message (0-25): ";
cin >> key;
message.setDisplacer(key);
message.msgEncripter(msg, key);
outputFile << msg;
outputFile.close();
for (int count = 0; count < 1; count++)
{
for (int i = 0; i <= 7; i++)
{
pass += getRandChar();
}
cout << pass << endl;
}
cout << "Input password " << pass << " ";
cin >> input;
if (input == pass)
{
//Make a local variable to read file
string encryptedMessage;
inputFile.open("SecretMSG.txt");
inputFile >> encryptedMessage;
inputFile.close();
cout << message.getMessage() << endl;
cout << "If you wish to decrypt the message, type in the password once again " << pass << ": ";
cin >> input;
if (input == pass)
{
message.msgDecripter(encryptedMessage);
cout << message.getDecription() << endl;
}
else
{
exit(EXIT_FAILURE);
}
}
else
{
exit(EXIT_FAILURE);
}
system("pause");
return 0;
}
In msgDecripter your string decriptedMsg creates a string with the size 0, so any decriptedMsg[i] = is undefined behavior.
In your msgEncripter you write string encriptedMsg = msg;, and because you create a copy of mgs the encriptedMsg has the same size.
So either you do string decriptedMsg = msg or string decriptedMsg = std::string(msg.size(), ' ');
But a more c++ like approach would be to use transform.
string encriptedMsg = msg;
std::transform(encriptedMsg.begin(), encriptedMsg.end(), encriptedMsg.begin(),
[](unsigned char c) -> unsigned char {
if( c == ' ') {
return c;
} else {
// ... your other encrypting logic ...
}
});
Or using msg as source and an empty string as target and utilize std::back_inserter.

Trying to update an array with huffman string code

My current program creates a huffman tree filled with nodes of ascii characters that are being read from a text file along with the amount of time they appear in the text file (frequency). In addition, it outputs unique codes for each character read based on frequency, this is done using my traverse function.
My problem: I have this string array that can hold codes for all 256 ascii values in my huffman function that by default is set to an empty string for each element. I have been trying to update my array by passing a parameter to my traverse function but it gives me an error.
Code E0413 - "No suitable conversion from std::string to char exists"
Parts of my code below along with some explanation of what the variables in my traverse function are:
'character' is the char that has been found in the text file
'frequency' gives the number of times a character is read in the text file
'traversecode' is the huffman code being generated by the traverse function
I have also commented out lines in my traverse function where I get the error.
struct node {
int frequency;
char character;
const node *child0;
const node *child1;
node(unsigned char c = 0, int i = -1) {
character = c;
frequency = i;
child0 = 0;
child1 = 0;
}
node(const node* c0, const node *c1) {
character = 0;
frequency = c0->frequency + c1->frequency;
child0 = c0;
child1 = c1;
}
bool operator<(const node &a) const {
return frequency > a.frequency;
}
void traverse(string codearray[256], string traversecode = "") const {
if (child0) {
child0->traverse(traversecode + '0'); // one line throwing the error
child1->traverse(traversecode + '1'); // second line that throws me the error
}
else {
codearray[int(character)] = traversecode;
cout << " " << character << " ";
cout << frequency;
cout << " " << traversecode << endl;
}
}
};
huffman function (function that contains array I would like to get updated)
void huffman(string code[256], const unsigned long long frequency[256]) {
priority_queue < node > q;
for (unsigned i = 0; i < 256; i++) {
if (frequency[i] == 0) {
code[i] = "";
}
}
for (int i = 0; i < 256; i++)
if (frequency[i])
q.push(node(i, frequency[i]));
while (q.size() > 1) {
node *child0 = new node(q.top());
q.pop();
node *child1 = new node(q.top());
q.pop();
q.push(node(child0, child1));
}
cout << "CHAR FREQUENCY HUFFMAN CODE" << endl;
q.top().traverse(code);
}
When you make the recursive call to traverse, you need to provide both parameters.
child0->traverse(codearray, traversecode + '0');
You're currently trying to pass what should be the second parameter as the first.
One other possible issue is that your code assumes that char is unsigned. If a char is signed, the access to codearray[int(character)] will access outside the bounds of codearray if the character is "negative" (or in the upper half of the ASCII table when using unsigned characters).

How to split a string by another string in Arduino?

I have a character array like below:
char array[] = "AAAA... A1... 3. B1.";
How can I split this array by the string "..." in Arduino? I have tried:
ptr = strtok(array, "...");
and the output is the following:
AAAA,
A1,
3,
B1
But I actually want output to be
AAAA,
A1,
3.B1.
How to get this output?
edit:
My full code is this:
char array[] = "AAAA... A1... 3. B1.";
char *strings[10];
char *ptr = NULL;`enter code here`
void setup()
{
Serial.begin(9600);
byte index = 0;
ptr = strtok(array, "..."); // takes a list of delimiters
while(ptr != NULL)
{
strings[index] = ptr;
index++;
ptr = strtok(NULL, "..."); // takes a list of delimiters
}
for(int n = 0; n < index; n++)
{
Serial.println(strings[n]);
}
}
The main problem is that strtok does not find a string inside another string. strtok looks for a character in a string. When you give multiple characters to strtok it looks for any of these. Consequently, writing strtok(array, "..."); is exactly the same as writing strtok(array, ".");. That is why you get a split after "3."
There are multiple ways of doing what you want. Below I'll show you an example using strstr. Unlike strtokthe strstr function do find a substring inside a string - just what you are looking for. But.. strstr is not a tokenizer so some extra code is required to print the substrings.
Something like this should do:
int main()
{
char array[] = "AAAA... A1... 3. B1...";
char* ps = array;
char* pf = strstr(ps, "..."); // Find first substring
while(pf)
{
int len = pf - ps; // Number of chars to print
printf("%.*s\n", len, ps);
ps = pf + 3;
pf = strstr(ps, "..."); // Find next substring
}
return 0;
}
You can implement your own split as strtok except the role of the second argument :
#include <stdio.h>
#include <string.h>
char * split(char *str, const char * delim)
{
static char * s;
char * p, * r;
if (str != NULL)
s = str;
p = strstr(s, delim);
if (p == NULL) {
if (*s == 0)
return NULL;
r = s;
s += strlen(s);
return r;
}
r = s;
*p = 0;
s = p + strlen(delim);
return r;
}
int main()
{
char s[] = "AAAA... A1... 3. B1.";
char * p = s;
char * t;
while ((t = split(p, "...")) != NULL) {
printf("'%s'\n", t);
p = NULL;
}
return 0;
}
Compilation and execution:
/tmp % gcc -g -pedantic -Wextra s.c
/tmp % ./a.out
'AAAA'
' A1'
' 3. B1.'
/tmp %
I print between '' to show the return spaces, because I am not sure you want them, so delim is not only ... in that case
Because you tagged this as c++, here is a c++ 'version' of your code:
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
class T965_t
{
string array;
vector<string> strings;
public:
T965_t() : array("AAAA... A1... 3. B1.")
{
strings.reserve(10);
}
~T965_t() = default;
int operator()() { return setup(); } // functor entry
private: // methods
int setup()
{
cout << endl;
const string pat1 ("... ");
string s1 = array; // working copy
size_t indx = s1.find(pat1, 0); // find first ... pattern
// start search at ---------^
do
{
if (string::npos == indx) // pattern not found
{
strings.push_back (s1); // capture 'remainder' of s1
break; // not found, kick out
}
// else
// extract --------vvvvvvvvvvvvvvvvv
strings.push_back (s1.substr(0, indx)); // capture
// capture to vector
indx += pat1.size(); // i.e. 4
s1.erase(0, indx); // erase previous capture
indx = s1.find(pat1, 0); // find next
} while(true);
for(uint n = 0; n < strings.size(); n++)
cout << strings[n] << "\n";
cout << endl;
return 0;
}
}; // class T965_t
int main(int , char**) { return T965_t()(); } // call functor
With output:
AAAA
A1
3. B1.
Note: I leave changing "3. B1." to "3.B1.", and adding commas at end of each line (except the last) as an exercise for the OP if required.
I looked for a split function and I didn't find one that meets my requirement, so I made one and it works for me so far, of course in the future I will make some improvements, but it got me out of trouble.
But there is also the strtok function and better use that.
https://www.delftstack.com/es/howto/arduino/arduino-strtok/
I have the split function
Arduino code:
void split(String * vecSplit, int dimArray,String content,char separator){
if(content.length()==0)
return;
content = content + separator;
int countVec = 0;
int posSep = 0;
int posInit = 0;
while(countVec<dimArray){
posSep = content.indexOf(separator,posSep);
if(posSep<0){
return;
}
countVec++;
String splitStr = content.substring(posInit,posSep);
posSep = posSep+1;
posInit = posSep;
vecSplit[countVec] = splitStr;
countVec++;
}
}
Llamada a funcion:
smsContent = "APN:4g.entel;DOMAIN:domolin.com;DELAY_GPS:60";
String vecSplit[10];
split(vecSplit,10,smsContent,';');
for(int i = 0;i<10;i++){
Serial.println(vecSplit[i]);
}
String input:
APN:4gentel;DOMAIN:domolin.com;DELAY_GPS:60
Output:
APN:4g.entel
DOMAIN:domolin.com
DELAY_GPS:60
RESET:true
enter image description here

problems encrypting char*

i have been working on this project for a week and i cant find the solution to my problems.
i'm making an encryptor which can encrypt/decrypt binary file(like .exe, .jpg etc).
i am able to correctly get the data from the binary file using vector.
but i cannot correctly encrypt/decrypt the data from the vector.
some code:
if (encryptFile)
{
Crypt crypt;
//TOencryptfile.open(writeFile, ios::binary | ios::out);
vector<char> buffer((istreambuf_iterator<char>(encryptFile)),(istreambuf_iterator<char>()));
cout << buffer.size() << endl;
_getch();
for (std::vector<char>::iterator i = buffer.begin(); i != buffer.end(); ++i) {
// encryption that fails
temp = crypt.getKeyFromString(&*i , key, strlen(&*i));
}
TOencryptfile.close();
encryptFile.close();
}
and the function getKeyFromString:
KEYCRYPT Crypt::getKeyFromString(KEYCRYPT text, KEYCHAR charkey, keylength length) {
int string_size = std::strlen(text);
KEYCRYPT textcrypt = new char[string_size + 1];
std::strcpy(textcrypt, text);
int key = strlen(charkey);
for (int i = 0; i < length; i++) {
if (strlen(text) != 0) {
textcrypt[i] = text[i] ^ charkey[i % (sizeof(charkey) / sizeof(char))];
//keylvl += text[i] ^ (int(charkey) + i) % key;
//keyfnl += keylvl[i] ^ (int(charkey) - i) * key;
}
}
return textcrypt;
}
and at last the types:
typedef char* KEYCRYPT;
typedef int KEY;
typedef char* KEYCHAR;
typedef int keylength;
does anybody know a good way to encrypt *i?
because my way does not work, it does not return the same when calling the function again with getKeyFromString(temp, key, strlen(temp))
well, according to the response of #Barmar:
#waterlight Put the file contents into a string and pass that to the crypto API.
i managed to fix the problem.
all i had to do was:
stringstream result;
std::copy(buffer.begin(), buffer.end(), std::ostream_iterator<char>(result, " "));
string now = result.str();
and everything worked.
thanks to everybody who replied!!