C Language: Advanced Caesarian Encryption


We continue to do homework from Problem set 2 in Computer science CS50 (Harvard). Last time, we learned how to encrypt text by shifting letters by a certain number (key) entered by the user. And this time we will solve the problem more complicated, it will be the Substitution.c program and it also encrypts the text by replacing some letters with others according to the principle that the user enters on the command line when the program starts. This principle looks like a string of letters of the alphabet arranged in a reversed order, as in the example:

$ ./substitution JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext:  HELLO
ciphertext: VKXXN

For example, the letter “H” should be replaced by the 8th letter from the entered string
JT R E KY A V OGDXPSNCUIZLFBMWHQ
1 2 3 4 5 6 7 8

— it’s “V”, because if you count in the usual alphabet ABCDEFGH…, then “H”— is the eighth letter.

A few points that might come in handy:

  • at the beginning of the program, after checking for input errors, you can make an array that will contain the indices of all 26 letters entered by the user, this array is convenient to use later to replace letters;
  • to check if all 26 letters are unique, it is convenient to introduce a variable to count the number of each letter in the input array.

Igroglaz solution:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

void build_index(char *AZ);
int main(int argc, char *argv[])
{
    int i, n, j, x;
    char text[1000]; // text input
    char cypher[1000]; // cypher output
    char AZ[26]; // alphabetical indexes

    /*** STEP 1 - check argv ***/

    // in case if user didn't input proper console argument
    if (!(argc == 2) || (strlen(argv[1]) != 26))
    {
        printf("Usage: ./substitution key");
        return 1;
    }

    // build A-Z and a-z indexes
    build_index(AZ);

    // check console argument for wrong or non-unique characters
    for (i = 0; i < 26; i++)
    {
        // capitalise letters
        if (argv[1][i] >= 'a' && argv[1][i] <= 'z')
            argv[1][i] = toupper(argv[1][i]);

        // take capital letter and compare it with each letter in index
        if (argv[1][i] >= 'A' && argv[1][i] <= 'Z')
        {
            for (j = 0; j < 26; j++)
            {
                // if letter found in indexes - make this index variable 0
                if (argv[1][i] == AZ[j])
                    AZ[j] = 0;
            }
        }
        else
        {
            printf("Error: entered wrong symbols as a key");
            return 1;
        }
    }

    // finally argv processing step: summ all indexes
    for (i = 0, j = 0; j < 26; j++)
        i += (int)AZ[j];
    // summ should be 0
    if (i > 0)
    {
        printf("Error: key must consist out of unique characters");
        return 1;
    }

    /*** STEP 2 - get phrase ***/

    // now lets get phrase to cipher
    printf("plaintext: ");

    for (i = 0, n = 0; ; i++)
    {
        scanf ("%c", &text[i]);        // get user input
        if (text[i] == '\n')
        {
            printf("\n");
            break;    // end input when user press 'Enter'
        }
        n++; // count number of input
    }

    /*** STEP 3 - sipher text ***/

    // now lets get phrase to cipher
    printf("ciphertext: ");

    // replace plaintext with cipher
    for (i = 0; i <= n; i++)
    {
        if (text[i] >= 'A' && text[i] <= 'Z')
        {
            x = (int)text[i] - 65;
            printf("%c", argv[1][x]);
        }
        else if (text[i] >= 'a' && text[i] <= 'z')
        {
            x = (int)text[i] - 97;
            printf("%c", tolower(argv[1][x]));
        }
        else
            printf("%c", text[i]);
    }

    getchar();
    getchar();
    return 0;
}

void build_index(char *AZ)
{
    int i, j;
    for (i = 0, j = 65; i < 26; i++) // note: AZ array elements are 0-25
        AZ[i] = j++;
}

Solution by Shtukensia:

#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

char rotate(char c, int n, int keys[]);

int main(int argc, string argv[])
{

// Check if user write key as string argv[]:
    if (argc != 2)
    {
        printf("Usage: ./substitution key\n");
        return 1;
    }

// Check if all key 26 characters of argv[] are alphabetical:
    int k = 1;
    int i = 0;
    int sum_of_key = 0;
    int key_for_letter = 0; // key number for changing character
    int keys [26]; // array for all key numbers for changing characters

    for (i = 0; argv[k][i]; i++)
    {
        int k_check = isalpha(argv[k][i]);
        if (k_check == 0)
        {
            printf("Key must contain characters.\n");
            return 1;
        }
        else if (k_check != 0)
        {
            int check_key = isupper(argv[k][i]); // check if key char is uppercase
            if (check_key > 0)
            {
                int letter_id = (argv[k][i]);
                key_for_letter = letter_id - 65;
                keys[i] = key_for_letter;
            }
            if (check_key == 0)
            {
                int letter_id = (argv[k][i]);
                key_for_letter = letter_id - 97;
                keys[i] = key_for_letter;
            }
            sum_of_key += 1;
        }
    }

// Check if lenth of key is OK

    if (sum_of_key != 26)
    {
        printf("Key must contain 26 characters.\n");
        return 1;
    }

// Check if each character of argv[] key is unique:

    for (int q = 0; keys[q]; q++)
    {
        for (int z = (q + 1); z <= (25 - q); z++)
        {
            if (keys[q] == keys[z])
            {
                printf("Key must contain 26 UNIQUE characters.\n");
                return 1;
            }
        }
    }


// Get user input of plaintxtx:
    printf("plaintext:");
    string plaintxtx = get_string("  ");
    int textlen = strlen(plaintxtx);


// Turn characters from plaintxtx to ciphertext with function
    char c; // character from plaintxtx
    char c_new; // newmade rotated character
    int n = 0; // index for shifting letter

    printf("ciphertext: ");

    int j = 0;
    for (j = 0; j < textlen; j++) // print char by char rotated letters
    {
        c = plaintxtx[j];
        c_new = rotate(c, n, keys);
        printf("%c", c_new);

    }

    printf("\n");
    return 0;
}

char rotate(char c, int n, int keys[])
{
    int check_c = isalpha(c); // check if char is letter

    if (check_c == 0) // if char is not letter, return as it is
    {
        return c;
    }

    else
    {
        char c_new = ' '; // rotated newmade character
        int check_upper = isupper(c); // check if char is uppercase

        if (check_upper > 0)
        {

            int c_asci = (c); // convert char LETTER to int ASCII number (A->65)
            int num_letter = (c_asci - 65); // find numer of upper letter in alphabet (index)
            int shifted_index = keys[num_letter]; // shift index of letter with key number
            c_new = shifted_index + 65; // convert ASCII number back to new letter

            return c_new;
        }

        else if (check_upper == 0)
        {
            int c_asci = (c); // convert char LETTER to int ASCII number (a->97)
            int num_letter = (c_asci - 97); // find numer of lower letter in alphabet (index)
            int shifted_index = keys[num_letter]; // shift index of letter with key number
            c_new = shifted_index + 97; // convert ASCII number back to new letter
            return c_new;
        }

        else
        {
            return 'N';
        }
    }
}

This entry was posted in C language (en). Bookmark the permalink.

Leave a Reply

🇬🇧 Attention! Comments with URLs/email are not allowed.
🇷🇺 Комментарии со ссылками/email удаляются автоматически.