Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 구현하는 플레이페어 암호(Playfair Cipher): 메시지 인코딩 및 디코딩 완전 가이드


플레이페어 암호(Playfair Cipher)는 단순 치환 암호처럼 문자 하나씩 암호화하는 것이 아니라, 두 글자씩 쌍(pair)으로 묶어 암호화하는 방식입니다.

플레이페어 암호에서는 가장 먼저 키 테이블(key table)을 생성합니다. 키 테이블은 평문을 암호화할 때 열쇠 역할을 하는 5×5 크기의 알파벳 격자입니다. 테이블에 들어가는 25개의 알파벳은 모두 고유해야 하며, 26개가 아닌 25개만 필요하기 때문에 일반적으로 알파벳 중 하나(J)는 표에서 제외됩니다. 따라서 평문에 J가 포함된 경우에는 I로 대체하여 처리합니다.

송신자와 수신자는 사전에 특정 키를 정합니다. 예를 들어 키가 'tutorials'라고 가정해 보겠습니다. 키 테이블의 첫 부분(왼쪽에서 오른쪽 방향)에는 해당 문구가 중복 문자를 제거한 상태로 배치되고, 나머지 칸은 아직 사용되지 않은 알파벳들을 자연스러운 순서대로 채워 넣습니다. 그렇게 완성된 키 테이블은 다음과 같습니다.

C++로 구현하는 플레이페어 암호(Playfair Cipher): 메시지 인코딩 및 디코딩 완전 가이드

플레이페어 암호의 처리 과정

먼저 평문 메시지를 두 글자씩의 쌍(digraph)으로 분할합니다. 글자 수가 홀수라면 마지막에 Z를 추가하여 짝을 맞춥니다. 예를 들어 "hide money"라는 메시지를 암호화한다고 하면 다음과 같이 나누어집니다.

HI DE MO NE YZ

암호화 규칙은 다음과 같습니다.

  • 두 글자가 같은 열에 있는 경우: 각 글자 바로 아래에 있는 글자를 선택합니다(맨 아래 행이라면 맨 위로 돌아갑니다). 'H'와 'I'는 같은 열에 있으므로 각각 아래 글자로 대체됩니다. HI → QC

C++로 구현하는 플레이페어 암호(Playfair Cipher): 메시지 인코딩 및 디코딩 완전 가이드

  • 두 글자가 같은 행에 있는 경우: 각 글자 바로 오른쪽에 있는 글자를 선택합니다(가장 오른쪽 열이라면 맨 왼쪽으로 돌아갑니다). 'D'와 'E'는 같은 행에 있으므로 각각 오른쪽 글자로 대체됩니다. DE → EF

C++로 구현하는 플레이페어 암호(Playfair Cipher): 메시지 인코딩 및 디코딩 완전 가이드

  • 위 두 경우에 모두 해당하지 않는 경우: 두 글자로 직사각형을 만들고, 각 글자의 수평 반대편 꼭짓점에 위치한 글자를 선택합니다.

C++로 구현하는 플레이페어 암호(Playfair Cipher): 메시지 인코딩 및 디코딩 완전 가이드

위 규칙들을 적용하면, 키 'tutorials'를 사용해 'hide money'를 암호화한 결과는 다음과 같습니다.

QC EF NU MF ZV

플레이페어 암호의 복호화는 동일한 과정을 역순으로 수행하면 됩니다. 수신자는 같은 키를 가지고 있으므로 동일한 키 테이블을 만들 수 있고, 이를 통해 해당 키로 생성된 모든 메시지를 복호화할 수 있습니다.

다음은 플레이페어 암호를 사용하여 메시지를 인코딩(및 디코딩)하는 C++ 프로그램입니다.

알고리즘

Begin
Function void play( int dir )
For it = msg.begin() to it != msg.end()
    If ( getPos( *it++, j, k ) )
       If ( getPos( *it, p, q) )
          If ( j == p )
             nmsg += getChar( j, k + dir )
             nmsg += getChar( p, q + dir )
          else if( k == q )
             nmsg += getChar( j + dir, k )
             nmsg += getChar( p + dir, q )
          else
             nmsg += getChar( p, k )
             nmsg += getChar( j, q )
          done
       done
    done
    msg = nmsg
done
End

C++ 예제 코드

#include <iostream>
#include <string>
using namespace std;
class playfair {
    public:
        string msg; char n[5][5];
    void play( string k, string t, bool m, bool e ) {
        createEncoder( k, m );
        getText( t, m, e );
        if( e )
            play( 1 );
        else
            play( -1 );
        print();
    }
    private:
    void play( int dir ) {
        int j,k,p,q;
        string nmsg;
        for( string::const_iterator it = msg.begin(); it != msg.end(); it++ ) {
            if( getPos( *it++, j, k ) )
            if( getPos( *it, p, q) ) {
                //for same row
                if( j == p ) {
                    nmsg += getChar( j, k + dir );
                    nmsg += getChar( p, q + dir );
                }
                //for same column
                else if( k == q ) {
                    nmsg += getChar( j + dir, k );
                    nmsg += getChar( p + dir, q );
                } else {
                    nmsg += getChar( p, k );
                    nmsg += getChar( j, q );
                }
            }
        }
        msg = nmsg;
    }
    void print() //print the solution {
        cout << "\n\n Solution:" << endl;
        string::iterator it = msg.begin(); int count = 0;
        while( it != msg.end() ) {
            cout << *it;
            it++;
            cout << *it << " ";
            it++;
            if( ++count >= 26 )
            cout << endl;
            count = 0;
        }
        cout << endl << endl;
    }
    char getChar( int a, int b ) { //get the characters
        return n[ (b + 5) % 5 ][ (a + 5) % 5 ];
    }
    bool getPos( char l, int &c, int &d ) { //get the position
        for( int y = 0; y < 5; y++ )
            for( int x = 0; x < 5; x++ )
                if( n[y][x] == l ) {
                    c = x;
                    d = y;
                    return true;
                }
        return false;
    }
    void getText( string t, bool m, bool e ) { //get the original message
        for( string::iterator it = t.begin(); it != t.end(); it++ ) {
            //to choose J = I or no Q in the alphabet.
            *it = toupper( *it );
            if( *it < 65 || *it > 90 )
                continue;
            if( *it == 'J' && m )
                *it = 'I';
            else if( *it == 'Q' && !m )
                continue;
            msg += *it;
        } if( e ) {
            string nmsg = ""; size_t len = msg.length();
            for( size_t x = 0; x < len; x += 2 ) {
                nmsg += msg[x];
                if( x + 1 < len ) {
                    if( msg[x] == msg[x + 1] ) nmsg += 'X';
                    nmsg += msg[x + 1];
                }
            }
            msg = nmsg;
        }
        if( msg.length() & 1 )
        msg += 'X';
    }
    void createEncoder( string key, bool m ) { //creation of the key table
        if( key.length() < 1 )
        key = "KEYWORD";
        key += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        string s = "";
        for( string::iterator it = key.begin(); it != key.end(); it++ ) {
            *it = toupper( *it );
            if( *it < 65 || *it > 90 )
                continue;
            if( ( *it == 'J' && m ) || ( *it == 'Q' && !m ) )
                continue;
            if( s.find( *it ) == -1 )
                s += *it;
        }
        copy( s.begin(), s.end(), &n[0][0] );
    }
};
int main( int argc, char* argv[] ) {
    string k, i, msg;
    bool m, c;
    cout << "Encrpty or Decypt? ";
    getline( cin, i );
    c = ( i[0] == 'e' || i[0] == 'E' );
    cout << "Enter a key: ";
    getline( cin, k);
    cout << "I <-> J (Y/N): ";
    getline( cin, i );
    m = ( i[0] == 'y' || i[0] == 'Y' );
    cout << "Enter the message: ";
    getline( cin, msg );
    playfair pf;
    pf.play( k, msg,m, c );
    return system( "pause" );
}

실행 결과

프로그램을 실행하고 복호화(d) 모드에서 키 'players', J↔I 변환 옵션 'y'를 입력한 뒤 암호문을 넣으면 다음과 같은 결과를 얻을 수 있습니다.

Encrpty or Decypt? d
Enter a key: players
I <-> J (Y/N): y
Enter the message: OK GC GC MZ MQ CF YA RL QH OM

Solution:
TH IS IS TU TO RI AL SP OI NT