강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

Tiz님의 프로필 이미지
Tiz

작성한 질문수

C++로 플레이페어 암호를 구현하려고 해요..

작성

·

327

0

// C++ program for encryption using Playfair Cipher
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

#define SIZE 30

// Function to convert the string to lowercase
void toLowerCase(char plain[], int ps)
{
    for (int i = 0; i < ps; i++)
    {
        if (plain[i] >= 'A' && plain[i] <= 'Z') // 대문자를 소문자로 변환
            plain[i] = tolower(plain[i]);
    }
}

// Function to remove duplicate characters from the key
void removeDuplicates(char key[], int &ks)
{
    int index = 0;

    for (int i = 0; i < ks; ++i)
    {
        int j;
        for (j = 0; j < i; ++j)
        {
            if (key[i] == key[j])
            {
                break;
            }
        }
        if (i == j)
        {
            key[index++] = key[i];
        }
    }

    key[index] = '\0';
    ks = index;
}

// Function to remove all spaces in a string
int removeSpaces(char *plain, int ps)
{
    int count = 0;
    for (int i = 0; i < ps; i++)
    {
        if (plain[i] != ' ')
            plain[count++] = plain[i];
    }
    plain[count] = '\0';
    return count;
}

// Function to generate the 5x5 key square
void generateKeyTable(char key[], int ks, char keyT[5][5])
{
    int i, j, k, *d;

    // a 26 character hashmap to store count of the alphabet
    d = (int *)calloc(26, sizeof(int));
    for (i = 0; i < ks; i++)
    {
        if (key[i] != 'j')
            d[key[i] - 97] = 2;
    }

    d['j' - 97] = 1;

    i = 0;
    j = 0;

    for (k = 0; k < ks; k++)
    {
        if (d[key[k] - 97] == 2)
        {
            d[key[k] - 97] -= 1;
            keyT[i][j] = key[k];
            j++;
            if (j == 5)
            {
                i++;
                j = 0;
            }
        }
    }

    for (k = 0; k < 26; k++)
    {
        if (d[k] == 0)
        {
            keyT[i][j] = (char)(k + 97);
            j++;
            if (j == 5)
            {
                i++;
                j = 0;
            }
        }
    }
}

// Function to search for the characters of a digraph
// in the key square and return their position
void search(char keyT[5][5], char a, char b, int arr[])
{
    int i, j;

    if (a == 'j')
        a = 'i';
    else if (b == 'j')
        b = 'i';

    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
            if (keyT[i][j] == a)
            {
                arr[0] = i;
                arr[1] = j;
            }
            else if (keyT[i][j] == b)
            {
                arr[2] = i;
                arr[3] = j;
            }
        }
    }
}

// Function to find the modulus with 5
int mod5(int a)
{
    return (a % 5);
}

// Function to make the plain text length to be even
int prepare(char str[], int ptrs)
{
    if (ptrs % 2 != 0)
    {
        str[ptrs++] = 'z';
        str[ptrs] = '\0';
    }
    return ptrs;
}

// Function for performing the encryption
void encrypt(char str[], char keyT[5][5], int ps)
{
    int i, a[4];

    for (i = 0; i < ps; i += 2)
    {
        search(keyT, str[i], str[i + 1], a);

        if (a[0] == a[2])
        {
            str[i] = keyT[a[0]][mod5(a[1] + 1)];
            str[i + 1] = keyT[a[0]][mod5(a[3] + 1)];
        }
        else if (a[1] == a[3])
        {
            str[i] = keyT[mod5(a[0] + 1)][a[1]];
            str[i + 1] = keyT[mod5(a[2] + 1)][a[1]];
        }
        else
        {
            str[i] = keyT[a[0]][a[3]];
            str[i + 1] = keyT[a[2]][a[1]];
        }
    }
}

void preparePlainText(char txt[], string mEncryption)
{
    int cnt = 0;

    mEncryption.erase(remove(mEncryption.begin(), mEncryption.end(), ' '), mEncryption.end());
    cout << "\n공백 제거 후: " << mEncryption << endl;

    char txt2[2 * SIZE];
    strcpy(txt2, mEncryption.c_str());

    cnt = 0;
    int len = strlen(txt2);

    for (int i = 0; i < len; i += 2){
        if (txt2[i] == txt2[i + 1])
        {
            txt[cnt++] = txt2[i];
            txt[cnt++] = 'x';
        }
        else
        {
            txt[cnt++] = txt2[i];
            txt[cnt++] = txt2[i + 1];
        }
    }
    len = strlen(txt);

    if (len % 2 == 1)
    {
        txt[len] = 'x';
        txt[len + 1] = '\0';
    }
    cout << "X 붙이고 자른 후: ";

    for (int i = 0; txt[i] != 0; i++)
    {
        cout << txt[i];

        if (i % 2 == 1)
        {
            cout << " ";
        }
    }
}

// Function to display the 5x5 key table including paired characters
void displayKeyTableWithPair(char keyT[5][5], char pair1, char pair2)
{
    cout << "\n5x5 Key Table:" << endl;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            if (keyT[i][j] == pair1)
            {
                cout << pair1 << "/" << pair2 << "\t";
            }
            else if (keyT[i][j] == pair2)
            {
                // To avoid duplicate display when pair1 == pair2
                if (pair1 != pair2)
                {
                    continue;
                }
                cout << pair1 << "/" << pair2 << "\t";
            }
            else
            {
                cout << keyT[i][j] << "\t";
            }
        }
        cout << endl;
    }
}

// Function to encrypt using Playfair Cipher
void encryptByPlayfairCipher(char str[], char key[])
{
    int ps, ks;
    char keyT[5][5];

    ks = strlen(key);
    ks = removeSpaces(key, ks);
    toLowerCase(key, ks);
    ps = strlen(str);
    toLowerCase(str, ps);
    ps = removeSpaces(str, ps);
    ps = prepare(str, ps);
    generateKeyTable(key, ks, keyT);
    encrypt(str, keyT, ps);
}

void generateKeyTableWithPair(char key[], int ks, char keyT[5][5], char pair1, char pair2)
{
    int i, j, k, *d;

    // a 26 character hashmap to store count of the alphabet
    d = (int *)calloc(26, sizeof(int));

    for (i = 0; i < ks; i++)
    {
        if (key[i] != 'j')
            d[key[i] - 97] = 2;
    }

    d['j' - 97] = 1;
    i = 0;
    j = 0;

    bool addedPair1 = false,
    addedPair2 = false;

    for (k = 0; k < ks; k++)
    {
        if (d[key[k] - 97] == 2)
        {
            d[key[k] - 97] -= 1;
            keyT[i][j] = key[k];
            j++;
            if (j == 5)
            {
                i++;
                j = 0;
            }
        }
    }

    // Additional loop to accommodate remaining characters
    for (k = 0; k < 26; k++)
    {
        if (d[k] == 0)
        {
            if (key[k] == pair1 && !addedPair1)
            {
                keyT[i][j++] = pair1;
                keyT[i][j++] = pair2;
                addedPair1 = true;
            }
            else if (key[k] == pair2 && !addedPair2)
            {
                keyT[i][j++] = pair2;
                keyT[i][j++] = pair1;
                addedPair2 = true;
            }
            else if (key[k] != pair1 && key[k] != pair2)
            {
                keyT[i][j++] = (char)(k + 97);
            }
            if (j == 5)
            {
                i++;
                j = 0;
            }
        }
    }
}

int main()
{
    char str[SIZE], key[SIZE];

    cout << "키 값 입력 ↓ " << endl;
    cin.getline(key, SIZE);
    int ks = strlen(key);
    removeDuplicates(key, ks);
    cout << "중복 제거된 키 값 -> " << key << endl;

    // Additional input for two characters
    char pair1, pair2;
    cout << "\n알파벳 2개 입력: ";
    cin >> pair1 >> pair2;

    cout << "\n평문 입력 ↓ " << endl;
    cin.ignore(); // Clear input buffer
    cin.getline(str, SIZE);

    cout << "\n";
    cout << "입력된 키 값 -> " << key << endl;
    cout << "입력된 평문 ->  " << str << endl;

    // Generate the 5x5 key table with pair1 and pair2 included
    char keyT[5][5];
    generateKeyTableWithPair(key, ks, keyT, pair1, pair2);
    // Display the 5x5 key table including paired characters
    displayKeyTableWithPair(keyT, pair1, pair2);

    // Prepare the plaintext and pair characters
    char txt[2 * SIZE];
    string plaintext(str);
    preparePlainText(txt, plaintext);

    encryptByPlayfairCipher(str, key);
    cout << "\n"
        << endl;
    cout << "암호문 : " << str << endl;

    return 0;
}

스크린샷 2023-12-08 오전 12.48.43.png이 코드를 실행시키면 아래처럼 나옵니다.. 키 테이블이 문제인데요.. 묶음처리해서 26개 알파벳 모두 넣으려고 하는데 generateKeyTableWithPair()이나

displayKeyTableWithPair()이 문제인가 싶어서 수정해볼려고 하는데도 잘 안돼서요.. 일부러 알파벳 철자 2개를 입력받아서 입력 받은 철자 2개를 묶는걸 의도한건데 어렵게되었어요..

어디가 문제인건지..고쳐주세요..ㅠㅠㅠㅠ

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.
Tiz님, C++로 플레이페어 암호를 구현하는 데 어려움을 겪고 계시군요. 코드와 설명을 바탕으로 문제가 발생하는 부분을 짚어 드리겠습니다.

먼저, generateKeyTableWithPair() 함수에서 키 테이블을 구성할 때 if (key[k] == pair1 && !addedPair1) 조건에서 key[k] 대신 k + 'a' 또는 char(k + 97)를 사용해야 합니다. 현재 코드에서는 key[k]를 사용하고 있는데, 이는 입력 키 문자열에서 k번째 문자를 나타내므로 알파벳 문자를 확인하는 것이 아닙니다.

generateKeyTableWithPair() 함수 내에서 다음과 같이 코드를 수정해 보세요:

// ... 이전 코드 생략 ...

for (k = 0; k < 26; k++) {
    // key[k] 대신 (char)(k + 97)를 사용하여 알파벳을 확인합니다.
    if (d[k] == 0) {
        char currentChar = (char)(k + 97);
        if (currentChar == pair1 && !addedPair1) {
            keyT[i][j++] = pair1;
            keyT[i][j++] = pair2;
            addedPair1 = true;
        }
        else if (currentChar == pair2 && !addedPair2) {
            keyT[i][j++] = pair2;
            keyT[i][j++] = pair1;
            addedPair2 = true;
        }
        else if (currentChar != pair1 && currentChar != pair2) {
            keyT[i][j++] = currentChar;
        }
        if (j == 5) {
            i++;
            j = 0;
        }
    }
}

// ... 이후 코드 생략 ...

또한, 아스키코드 값 ‘j’가 97가 아닌 106임을 고려해야 합니다.

이와 같이 코드를 변경한 후 다시 실행하면, 입력한 두 문자를 묶어 5x5 키 테이블을 생성하는 부분이 올바르게 동작할 것입니다.

혹시 해결되지 않는 문제가 있거나 추가적인 도움이 필요한 경우, 인프런의 문의하기를 통해 지원을 요청하실 수도 있습니다.

플레이페어 암호 구현에 성공하시길 바랍니다!

Tiz님의 프로필 이미지
Tiz

작성한 질문수

질문하기