Search code examples
cc-stringsvigenere

Vigenere cipher decoding not working properly


I am writing a vigenere cipher to be used as part of a loadable kernel module. Thus, I cannot use the string library. This is why I have included separate loops to get the key and input lengths as well. The include statement and the main are only included for testing.

Whenever I use a key that is not all caps, the program will crash due to an address sanitizer error. This only happens when I include the code that is supposed to convert the key input to uppercase. I am unsure of where this is incorrect, as my method to convert to uppercase is the same as I have seen on stack overflow in the past. It will run fine and not crash without those lines.

In addition, the decoding phase is not working as expected, it is giving the incorrect decoded message. The only possible problem that I can imagine is where I allow the input to contain spaces, but I do not think that is the issue since I am simply adding a space to the string. I would really appreciate some input as to where I am going wrong in this code. The complete error when attempting to convert to uppercase is:

==25694==ERROR: AddressSanitizer: BUS on unknown address 0x00010c98ae80 (pc 0x00010c989ac2 bp 0x7ffee3277610 sp 0x7ffee3277440 T0)
    #0 0x10c989ac1 in encrypt (vig:x86_64+0x100001ac1)
    #1 0x10c98aca1 in main (vig:x86_64+0x100002ca1)
    #2 0x7fff5c419ef8 in start (libdyld.dylib:x86_64+0x16ef8)

==25694==Register values:
rax = 0x000000010c98ae80  rbx = 0x00007ffee3277440  rcx = 0x000000010c98ae4b  rdx = 0x0000000000000004  
rdi = 0x000000010c98ae80  rsi = 0x000000010c98ae4b  rbp = 0x00007ffee3277610  rsp = 0x00007ffee3277440  
 r8 = 0x00001000219315d0   r9 = 0x0000000000000004  r10 = 0x0000000000000000  r11 = 0x0000000000000000  
r12 = 0x0000000000000000  r13 = 0x0000000000000000  r14 = 0x0000000000000000  r15 = 0x0000000000000000  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: BUS (vig:x86_64+0x100001ac1) in encrypt
==25694==ABORTING
Abort trap: 6

Here is my code:

#include<stdio.h>
#include<stdlib.h>
char* encrypt(char* input, char* key)
{
    int keyLength = 0;
    int inputLength = 0;
    int i;
    int j;
    for(i = 0; key[i] != '\0'; i++) //Get the length of the key
    {
        keyLength++;
    }
    for(i = 0; input[i] != '\0'; i++) //Get the length of the input
    {
        inputLength++;
    }
    for (i = 0; i < keyLength; i++)
    {
        if(key[i] >= 'a' && key[i] <= 'z')
        {
             key[i] = key[i] - 'a' + 'A';
        }
    }

    char* encryptedMessage = (char *)malloc((inputLength+1)*sizeof(char)); //Malloc for the encrypted message
    char fixedKey[inputLength + 1];
    if(inputLength < keyLength)
    {
        for(i =0; i < inputLength; i++)
        {
            fixedKey[i] = key[i];
        }
    }
    for(i = 0, j = 0; i < inputLength; ++i, ++j) //If the key length is shorter than message length, loop the key to correct length
    {
        printf("Entered Loop\n");
        if(j == keyLength)
            j = 0;
        fixedKey[i] = key[j];
    }
    fixedKey[i] = '\0';
    for(i = 0; i < inputLength; ++i) //Encryption
    {
        if(input[i] == ' ')
        {
            encryptedMessage[i] = ' ';
            continue;
        }
        encryptedMessage[i] = ((input[i] + fixedKey[i]) % 26) + 'A';
    }
    encryptedMessage[i] = '\0';
    return encryptedMessage;
}
char* decrypt(char* input, char* key)
{
    int keyLength = 0;
    int inputLength = 0;
    int i;
    int j;
    for(i = 0; key[i] != '\0'; i++) //Get the length of the key
    {
        keyLength++;
    }
    for(i = 0; input[i] != '\0'; i++) //Get the length of the input
    {
        inputLength++;
    }
    for (i = 0; i <keyLength; i++)
    {
        if(key[i] >= 'a' && key[i] <= 'z')
        {
            key[i] = key[i] - 'a' + 'A';
        }
    }
    char* decryptedMessage = (char *)malloc((inputLength+1)*sizeof(char));
    char fixedKey[inputLength + 1];
    if(inputLength < keyLength)
    {
        for(i =0; i < inputLength; i++)
        {
            fixedKey[i] = key[i];
        }
    }
    for(i = 0, j = 0; i < inputLength; ++i, ++j) //Fix the key length if needed
    {
        if(j == keyLength)
            j = 0;
        fixedKey[i] = key[j];
    }
    fixedKey[i] = '\0';
    for(i = 0; i < inputLength; ++i) //Decryption
    {
        if(input[i] == ' ')
        {
            decryptedMessage[i] = ' ';
            continue;
        }
        decryptedMessage[i] = (((input[i] - fixedKey[i]) + 26) % 26) + 'A';
    }
    decryptedMessage[i] = '\0';
    return decryptedMessage;
}
int main()
{
    char* encrypted = encrypt("The quick brown fox jumps over lazy dogs","key");
    char* decrypted = decrypt(encrypted,"key");
    printf("Encrypted string is: %s\nDecrypted String is: %s\n",encrypted,decrypted);
    return 0;
}

Solution

  • You're attempting to modify a string literal.

    You call encrypted as:

    encrypt("The quick brown fox jumps over lazy dogs","key");
    

    Then in encrypt, you modify the second parameter:

    key[i] = key[i] - 'a' + 'A';
    

    String literals are read-only, and attempting to modify them invokes undefined behavior.

    Make a local copy of key and modify that when performing the upper/lower case conversion.