0

I've been working on a cipher based project, and I wanted to prep the encrypted string for use with the RF24 library. Since the payload size for the RF24 module is 32 bytes, I wanted to stick with that size permanently. The key number (against which the encryption keys are stored) has to be embedded at the end of the char array, and I was converting it to a char to embed. To make the message up to 31 bytes if it was smaller than 31 bytes, I am padding with zeroes.

The cipher functions themselves (namely loadInput(), cipherText() and originalText()), work perfectly; I have tested these by themselves numerous times.

However, the other two functions I wrote for padding and de-padding are behaving erratically.

My code:

const String keys[] = {
"TTZUZRZJHP",
"SUENIFKGAT",
"CEXGWKMCVQ",
"SIACAKRFM",
"CSMKSWSNLH",
"IPIJWROJBB",
"SZSGAMYJGJ",
"BIHLBNUIJS",
"UTFGSQAISS",
"SSPXJXURJV",
"XPDRYPOFAC",
"DROIFANPZE",
"DKTZXUQLAM",
"UDHAWMAJTG",
"HKTQMEPWXS",
"IRUQAHZSBP",
"ZHZAAGTMTN",
"EHORTISSLQ",
"NYZZQALWTP",
"PEEGDJLQLQ",
"UNQGHTXFSG",
"NOBSTVFLAX",
"GQJYEVUNCX",
"UTJDNOCLSP",
"XQNGBDOBEN",
"FURHLIZSIN",
"AAAPEIGRHI",
"QWQFCCVFPV",
"KZEFJHUJWB",
"NDJNLHURJO"
};

char readyToSend[32]; //global array, which is to be transmitted via RF24
char recieved[32]; // global array, which is to be recieved via RF24
int keyRecieved; //global key number, which is to be embedded as the last char recieved[]

String loadInput() { //this functions takes the input string and checks it's validity
  bool isValid = true;
  String(inputStr);
  do {
    Serial.println("Enter valid input. Only enter ALPHABETIC characters. ONLY 31 CHARS MAX.");
    Serial.println("Whitespaces are valid but commas and fullstops are not");
    while (Serial.available () == 0) {}
    inputStr = Serial.readString();
    int inputLength = inputStr.length();

    for (int i=0; i<inputLength; i++) {
      if (inputLength>31) {
        Serial.println("Input longer than 31 chars.");
        isValid = false;
        break;
      } else if (inputStr[i] > 95 && inputStr[i] < 123) {
        inputStr[i] -= 32;
      } else if (isWhitespace(inputStr[i])) {
      } else if (!isAlpha(inputStr[i])) {
        isValid = false;
        break;
      }
    }
  } while (isValid == true);

  inputStr.remove((inputStr.length()-2), 2);
  return inputStr;
}

String cipherText(String str,const String key) { //this function encrypts the message, and returns the encrypted version
  String cipher_text; 
  for (int i=0; i<str.length(); i++) { 
    if (isWhitespace(str[i])) {
      cipher_text += ' '; 
    } else {
      char x = (str[i] + key[i%key.length()]) %26; 
      x += 'A'; 
      cipher_text += x; 
    }
  } 
  Serial.println(cipher_text); 
  return cipher_text;
} 
  
String originalText( String cipher_text,const String key) { //this function decrypts the message, and returns the decrypted version
  String orig_text; 
  
  for (int i=0 ; i<cipher_text.length(); i++) { 
    if (isWhitespace(cipher_text[i])) {
      orig_text += ' ';
    } else {
      // converting in range 0-25 
      char x = (cipher_text[i] - key[i%key.length()] + 26) %26; 
      // convert into alphabets(ASCII) 
      x += 'A'; 
      orig_text += x; 
    }
  } 
  return orig_text;
} 

void prepForTransmit(String input, int keyNumber) { //this function makes pads the string upto 31 with '0', then embeds key
  input.toCharArray(readyToSend, 32);
  int zeroesStart = input.length();
    
  for (int i=zeroesStart; i<32; i++) {
    readyToSend[i] = '0';
  }
    
  char keyNumberAsChar = (char)(keyNumber + 65);
  readyToSend[31] = keyNumberAsChar;
  return;
}

String PrepForDecode() { //this function makes exctracts key, then removes padding
  keyRecieved = (recieved[31] - 65);
  String toEdit = String(recieved);
  toEdit.remove(31, 1);

  if (toEdit.indexOf('0') != -1) {
    toEdit.remove(toEdit.indexOf('0'), (31-toEdit.indexOf('0')));
  } else {
  }
  return toEdit;
}
  
void setup() { // TEST CODE
  Serial.begin(9600);
  randomSeed(analogRead(A0)); //SEED RANDOM FUNCTION
  String(text) = loadInput(); //GET INPUT
  Serial.println(text); //PRINT INPUT      <--------------------------------------
  int keynumber = random(25); //              |
  String encrypted_message = cipherText( text, keys[keynumber]);  //ENCRYPT THIs _|
  Serial.println("Using key number ");
  Serial.println(keynumber);
     
  prepForTransmit(encrypted_message, keynumber); // PADDING AND ADD KEYNUMBER
  Serial.println("Message to trasmit through radio is: ");
  Serial.println(readyToSend);  // PRINT PREPPED CHAR ARRAY
  for (int i=0; i<32; i++) {
    recieved[i] = readyToSend[i]; // COPY PREPPED ARRAY TO EMULATE RECEPTION FROM RADIO
  }
  String toDecode = PrepForDecode(); // PREP RECIEVED STRING FOR DECODING (REMOVE PADDING, EXTRACT KEY)

  Serial.println(originalText( toDecode , keys[keyRecieved])); // PRINT DECODED STRING
}

void loop() { //main program

My serial output:

22:18:59.596 -> Whitespaces are valid but commas and fullstops are not
22:19:08.255 -> THIS PROJECT IS A MESS
22:19:08.290 -> LPIU ZITVWKT IC F EMSU
22:19:08.325 -> Using key number 
22:19:08.325 -> 3
22:19:08.325 -> Message to trasmit through radio is: 
22:19:08.393 -> LPIU ZITVWKT IC F EMSU000000000D⸮!
22:19:08.428 -> THIS PROJECT IS A MESSLFRP HATTWAC WK F ECBP>8BJHJ@9ER:3

"LPIU ZITVWKT IC F EMSU000000000D⸮!" is very unexpected, since there should only be 32 chars, and here there are 34.

Furthermore, the behavior here: "THIS PROJECT IS A MESSLFRP HATTWAC WK F ECBP>8BJHJ@9ER:3" is something I absolutely cannot understand.

I am baffled, and I would really appreciate help. I apologize in advance if the error is something small or stupid, but I cannot understand what's going on here.

6
  • 4
    Two words: "Null termination". You haven't terminated your strings properly. Commented Feb 1, 2021 at 18:32
  • @Majenko I thought converting from char array to String meant it was automatically null terminated? And the reason I have been using char arrays is to not have to deal with the null termination char. Commented Feb 2, 2021 at 1:54
  • @Majenko You were right! Apparently the String constructor doesn't handle the null termination with a char array input. Null terminating the string fixed the problem! Thank you! Commented Feb 2, 2021 at 3:43
  • 1
    Well, there isn't actually a String constructor for an array of char. There's one for a pointer to const char, which is completely unaware of the size of the array that the pointer was formed from. Commented Feb 2, 2021 at 3:47
  • 1
    why store literals as String classes instead of cstrings? seems unnecessary.... Commented Feb 2, 2021 at 18:15

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.