1

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. – Majenko Feb 1 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. – Okabe_ Feb 2 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! – Okabe_ Feb 2 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. – timemage Feb 2 at 3:47
  • @timemage I didn't know that. Thank you! I'm sure someone else who's found himself in a corner like me will find this useful! – Okabe_ Feb 2 at 3:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.