1

I'm working on this assignment where I'm taking a user input string, a key of the same or greater length, and using that to perform a Running Key cipher to encrypt and decrypt the text. Encryption is working, but decryption is not.

Looking manually at the Running Key table, I found that "ice" with a key of "did" would encrypt to "lkh" and that checks out. Looking back at the table, I found that for "lkh" to be turned into "ice", the key would have to change to "xsx" and for a moment, thought it'd be easy because I mistakenly thought it was "sxs" which is "did" with each letter shifted forward 15 letters. It's actually more arbitrary than that with the "d"'s shifting 20 letters and the "i" shifting only 10 letters to make "xsx".

I'm not sure what to put in my decrypt(), getDecryptedText(), or decryptionKey() functions to make this work, or if I was even on the right track trying to shift the letters. I imagine I must be, but my current thinking is that it may take some sort of loop to determine how many letters each character in the key should shift forward to.

#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
#include <cctype>

// Running Key Cipher Explanation
// http://practicalcryptography.com/ciphers/classical-era/running-key/

void encrypt(std::string&, std::string&, std::string&);
void decrypt(std::string&, std::string&, std::string&);
char getEncryptedText(char p, char k);
char getDecryptedText(char p, char k);
std::string decryptionKey(std::string&);
void getKeyIndex(int &i, std::string &key);

int main() {

  // Initialization
  std::string input;
  std::string key;

  std::string encryptedText;
  std::string decryptedText;

  // Assignment
  std::cout << "Enter secret message: ";
  std::getline(std::cin, input);
  std::cout << "Enter key (longer than message): ";
  std::getline(std::cin, key);

  // Remove spaces
  input.erase(remove_if(input.begin(), input.end(), isspace), input.end());
  key.erase(remove_if(key.begin(), key.end(), isspace), key.end());

  // Exit if key length < secret text
  if (key.length() < input.length()) {

    std::cout << "The encryption key must be longer than the message." 
    << std::endl;

    return 1;

  }

  // Encrypt the text
  encrypt(input, key, encryptedText);  

  // Display encrypted text to user
  std::cout << "\nThe encrypted text is:" << std::endl;  
  std::cout << encryptedText << std::endl;

  // Decrypt the text
  decrypt(encryptedText, key, decryptedText);

  // Display decrypted text to user
  std::cout << "\nThe decrypted text is:" << std::endl;  
  std::cout << decryptedText << std::endl;

  return 0;
}

void encrypt(std::string &input, std::string &key, std::string &encryptedText) {

  std::string::iterator i;
  std::string::iterator j;

  // Contains the encrypted version of the text
  encryptedText = "";

  // Encrypt every character in the input string
  for(i = key.begin(), j = input.begin(); j < input.end();) {

    // Remove non-letters from text
    if (!isalpha(*j)) {
      j++;
      continue;
    }

    // get encrypted char
    encryptedText += getEncryptedText(tolower(*j),tolower(*i));

    i++;
    j++;
  }
}

char getEncryptedText(char p, char k) {

  // Number to be converted into the nth letter in the alphabet
  int encryptedText;

  encryptedText = p + k;

  if (encryptedText >= 219) {

    return (char) (encryptedText - 123);

  }

  return (char)(encryptedText - 97);
}

void decrypt(std::string &encryptedText, std::string &key, std::string &decryptedText) {

  std::string::iterator i;
  std::string::iterator j;

  // Contains the decrypted version of the text
  decryptedText = "";

  // Change key to decrypt
  key = decryptionKey(key);

  // Decrypt every character in the input string
  for(i = key.begin(), j = encryptedText.begin(); j < encryptedText.end();) {

    // get decrypted char
    decryptedText += getDecryptedText(tolower(*j),tolower(*i));

    i++;
    j++;
  }
}

char getDecryptedText(char p, char k) {

  // Number to be converted into the nth letter in the alphabet
  int decryptedText;

  decryptedText = p + k;

  // If it gets passed z, go back to a
  if (decryptedText >= 219) {

    return (char) (decryptedText - 123);

  }

  return (char)(decryptedText - 98);
}

std::string decryptionKey(std::string &key) {

  for (int i = 0; i < key.length(); i++) {

    // Store integer ASCII value of char
    int asc = key[i];

    int rem = asc - (26 - (key[i] - 'a'));

    int m = rem % 26;

    key[i] = (char)(key[i] + 15);

  }

  // Decryption Key cout for testing
  std::cout << "Altered key: " << key; 

  return key;
}
  • Unrelated to your problem, but please read [Why should I not #include ?](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) – Some programmer dude Dec 11 '19 at 08:19
  • Yes, I've noticed that it makes the program slower to run and I wouldn't use it if I were going for efficiency, but thank you. – HeyYouPikachu Dec 11 '19 at 15:47

1 Answers1

0

getEncryptedText can be simplified to:

char getEncryptedText( char p, char k )
{
  return ( ( p - 'a' ) + ( k - 'a' ) ) % 26 + 'a';
}

I've replaced magic numbers with the actual character values to make the code easier to read.

If we make sure that getDecryptedText is the exact reverse of getEncryptedText there is no need to modify the key.

char getDecryptedText( char p, char k )
{
  return ( ( p - 'a' ) - ( k - 'a' ) + 26 ) % 26 + 'a';
}

The +26 is a fiddle to make sure the value is positive as the modulo won't produce the correct result for negative numbers.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60