Skip to main content

5th and 6th seminar

For this bonus you can get at maximum 2.5 K₡.

Source

Introduction

In this bonus you will implement few functions that will be used together for implementing a very special cipher.

Task no. 1: Reverse (0.5 K₡)

Write a function char* reverse(const char* text) that returns copy of the input string in reversed order (also uppercase).

In case you are given NULL, return NULL.

Example (more in tests):

char* reversed = reverse("Hello world!");

printf("%s\n", reversed);
// "!DLROW OLLEH"

if (reversed != NULL) {
free(reversed);
}

Task no. 2: Vigenère (0.5 K₡)

Vigenère cipher is similar to the Caesar cipher, but you also have a key that is used for encrypting (or decrypting).

Your task is to write two functions:

  • char* vigenere_encrypt(const char* key, const char* text) for encrypting
  • char* vigenere_decrypt(const char* key, const char* text) for decrypting

In both of those you should return uppercase characters.

Meaning of the parameters you are given:

  • key - String that represents key that is used for *crypting. It consists of one word and can have only characters of the alphabet. Does not matter if they are uppercase or lowercase.
  • text - String that is to be *crypted.

Function returns address of the encrypted (or decrypted) string. Or NULL in case error occurs.

Example:

char *encrypted = vigenere_encrypt("CoMPuTeR", "Hello world!");

printf("%s\n", encrypted);
// "JSXAI PSINR!"

if (encrypted != NULL) {
free(encrypted)
}

Bonus part (0.5 K₡)

If you can utilize helper function that would do both encrypting and decrypting, you can gain 0.5 K₡.

Usage of true/false to decide path in code is prohibited. It leads to merging of both functions into one. Point of this part is to discover a way to do this generically in such way that there are no separate paths for one or the other. One function with no branching for both of them, parametrization is your friend :)

Task no. 3: Bit madness (0.5 K₡)

This is a state of the art crypto. Please do not share :)

For encrypting:

  1. Split the character that is to be encrypted in halves (4 and 4 bits each).
  2. Bits in 1st half are to be split into pairs. Swap bits in those pairs.
  3. Then use the 4 bits that you created in the 2nd step for XOR with the other 4 bits.

This simple and ingenious principle will be illustrated on the following example. String we want to encrypt is Hello world!. We need to encrypt each letter separately, so we will demonstrate on letter H:

  1. Letter H is represented in ASCII as 72.

    72 represented in binary is: 01001000. So first 4 bits are: 0100 and last 4 bits are 1000.

  2. First half of bits (0100) consists of 2 pairs (01 and 00) which we swap (01 ~> 10 and 00 ~> 00). That way we get 1000.

  3. That half is used for xor with the other 4 bits:

        1000  // second half
    XOR 1000 // first half after 2nd step
    --------
    0000
  4. Now we combine both halves (first one is 1000, which we got from the 2nd step and second one is 0000, which we got from the 3rd step) and get 10000000, which is encrypted character H using this method.

In case of decryption, reverse those steps.

Your task is to implement functions:

  • unsigned char* bit_encrypt(const char* text)
  • char* bit_decrypt(const unsigned char* text)

Example:

unsigned char* encrypted = bit_encrypt("Hello world!");

for (int i = 0; i < 12;i++) {
printf("%x ", encrypted[i]);
//80 9c 95 95 96 11 bc 96 b9 95 9d 10
}

if (encrypted != NULL) {
free(encrypted);
}

Task no. 4: All combined to BMP (0.5 K₡)

Authors of the BMP cipher are non-disclosed :)

Create pair of functions:

  • unsigned char* bmp_encrypt(const char* key, const char* text)
  • char* bmp_decrypt(const char* key, const unsigned char* text)

BMP cipher consists of following steps for encrypting:

  1. Reverse the input string
  2. Use Vigenere on the string you got from step #1
  3. Use bit madness on the string you got from step #2

For decrypting, reverse the steps.

Submitting

In case you have any questions, feel free to reach out to me.