Block-Cipher (Lösung)

Code aus der Vorlesung

Den folgenden Code haben wir zusammen erarbeitet.

Wichtig: Nützlicher als das fertige Programm ist das Durcharbeiten der in der Vorlesung gezeigten Schritt-für-Schritt-Vorgehensweise. Der Code dort ist zwar nicht mit dem Code aus der Vorlesung identisch; er wird jedoch Schritt für Schritt entwickelt und ist ebenfalls eine vollständige Lösung.

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

#define BLOCKSIZE 3
#define ZEROCHAR '0'

void extract_block(string cleartext, int start_pos, char target[]);
void print_block(string block);
void permute_block(string current_block, int key_arr[]);
int validate_key(int key_arr[]);

int main(int argc, string argv[])
{
    // Der Permutationsschlüssel “201” bedeutet:
    // Position 0 geht nach 2, Position 1 geht nach 0,
    // Position 2 geht nach 1. Für den ersten Block
    // heißt das: HAL -> ALH
    /*
       HAL <= Quelle
       012

       201 <= Permutation = Index in der "Quelle"
       012 <= Pos. 2 im String geht an Stelle 0 ("Ziel")
    */

    // ./permute 201 VSCODE
    if (argc != 3)
    {
        printf("Usage: ./permute Permutation String\n");
        return 1;
    }

    string key_string  = argv[1];
    string cleartext   = argv[2];

    int key_arr[3];
    printf("Key: ");
    // TODO refactor into separate function
    for (int i = 0; i < BLOCKSIZE; i++)
    {
        key_arr[i] = key_string[i] - ZEROCHAR;
        printf("%i ", key_arr[i]);
    }
    printf("\n");
    if(! validate_key(key_arr))
    {
        printf("Key is invalid!\n");
        return 2;
    }


    //printf("Input: %s %s\n", permutation, cleartext);

    /*
      FOR pos = 0 BIS length(cleartext) SCHRITTWEITE SIZE
        AUSGABE "Block beginnt bei " + pos
        FOR pos_im_block = 0 BIS < 3 SCHRITTWEITE 1
            AUSGABE cleartext[ pos + pos_im_block ]
        AUSGABE " "
    */
   for (int pos = 0; pos < strlen(cleartext); pos += BLOCKSIZE)
   {
        char current_block[3];
        extract_block(cleartext, pos, current_block);

        printf("BEFORE: ");
        print_block(current_block);

        // permute block
        /*
            HAL <= Quelle
            012

            201 <= Permutation = Index in der "Quelle"
            012 <= Pos. 2 im String geht an Stelle 0 ("Ziel")
        */

        // overwrite current block with permuted block
        permute_block(current_block, key_arr);

        printf(" - AFTER: ");
        print_block(current_block);

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

void extract_block(string cleartext, int start_pos, char target[])
{
    for (int pos_in_block = 0; pos_in_block < BLOCKSIZE; pos_in_block++)
    {
        target[pos_in_block] = cleartext[ start_pos + pos_in_block ];
    }
}

void print_block(string block)
{
    for (int i = 0; i < BLOCKSIZE; i++)
    {
        printf("%c", block[i]);
    }
}


// overwrite current block with permuted block
/*
    current_block has size BLOCKSIZE
    key_arr[0] = 2 means: take element 2 from
                          current_block and place
                          it in position 0
*/
void permute_block(string current_block, int key_arr[])
{
    char temp[3];
    for (int i=0; i < BLOCKSIZE; i++)
    {
        temp[i] = current_block[key_arr[i]];
    }
    for (int i=0; i < BLOCKSIZE; i++)
    {
        current_block[i] = temp[i];
    }
}

// assume key_arr has length 3
int validate_key(int key_arr[])
{
    // div. Prüfungen
    int anzahl_der_zahlen[3] = {0, 0, 0};

    for (int i = 0; i < BLOCKSIZE; i++)
    {
        if (key_arr[i] >= BLOCKSIZE || key_arr[i] < 0)
        {
            return 0;
        }
        // zähle wie oft jede Zahl vorkommt (erhöhe um 1)
        anzahl_der_zahlen[ key_arr[i] ]++;

    }

    for (int i = 0; i < BLOCKSIZE; i++)
    {
        if(anzahl_der_zahlen[i] != 1)
        {
            return 0;
        }
    }
    return 1;
}