C++
 Computer >> コンピューター >  >> プログラミング >> C++

シーザー暗号を実装するC++プログラム


シーザー暗号とは

シーザー暗号は、平文の各文字を別の文字に置き換えることで暗号文を作り出す「単一換字式暗号(モノアルファベット暗号)」の一種です。換字式暗号の中でも最も基本的でシンプルな方式とされています。

この暗号方式は、一般的に「シフト暗号」とも呼ばれます。その考え方は、各アルファベットを0〜25の範囲内の固定した数だけ「ずらした」別のアルファベットに置き換えるというものです。

この方式では、送信者と受信者があらかじめ「秘密のシフト数」を共有しておきます。この0〜25の間の数値が、暗号化の鍵(キー)として機能します。

特に「3文字ずらす」場合には、このシフト暗号を指して「シーザー暗号」と呼ぶことがあります。名称の由来は、古代ローマのユリウス・カエサルが軍事通信にこの方式を用いたことだと言われています。

暗号化・復号化のプロセス

  • 平文の文字を暗号化するとき、送信者はスライド式の定規を平文の最初の文字列の下に当て、秘密のシフト数の分だけ左方向にスライドさせます。

  • そして、平文の文字を、その下に位置するスライド定規上の文字へと置き換えます。以下の図は、シフト数を3と合意した場合の処理結果を示したものです。この場合、平文「tutorial」は暗号文「wxwruldo」に変換されます。シフト数3のときの暗号用アルファベットは次の通りです。

シーザー暗号を実装するC++プログラム

  • 暗号文を受け取った受信者も秘密のシフト数を知っているため、スライド定規を暗号文アルファベットの下に当て、今度は合意されたシフト数(ここでは3)の分だけ右方向にスライドさせます。

  • 続いて、暗号文の文字を、その下のスライド定規上の平文の文字に置き換えます。これにより、暗号文「wxwruldo」は「tutorial」として復号されます。シフト数3で暗号化されたメッセージを復号するには、下図のように「−3」のシフトで平文用アルファベットを生成すればよいのです。

シーザー暗号を実装するC++プログラム

以上の処理をC++で実装した例を以下に示します。

手順と疑似コード

メッセージと鍵を入力として受け取ります。

暗号化の場合

  • 入力: tutorial
  • 出力: wxwruldo

復号化の場合

  • 入力: wxwruldo
  • 出力: tutorial

暗号化の疑似コード

Begin
    For i = 0 to msg[i] != '\0'
      ch = msg[i]
    // 小文字の暗号化
      If (ch >= 'a' and ch <= 'z')
         ch = ch + key
         if (ch > 'z')
            ch = ch - 'z' + 'a' - 1
         done
         msg[i] = ch
    // 大文字の暗号化
      else if (ch >= 'A' and ch <= 'Z')
         ch = ch + key
         if (ch > 'Z')
            ch = ch - 'Z' + 'A' - 1
         done
         msg[i] = ch
      done
    done
    Print Encrypted message
End

復号化の疑似コード

Begin
    For i = 0 to msg[i] != '\0'
      ch = msg[i]
    // 小文字の復号化
      if(ch >= 'a' and ch <= 'z')
         ch = ch - key
         if (ch < 'a')
            ch = ch + 'z' - 'a' + 1
      done
      msg[i] = ch
    // 大文字の復号化
      else if (ch >= 'A' and ch <= 'Z')
         ch = ch - key
         if (ch < 'A')
            ch = ch + 'Z' - 'A' + 1
         done
         msg[i] = ch
      done
    done
    Print decrypted message
End

C++による実装例

#include<iostream>
#include<string.h>
using namespace std;
int main() {
    cout<<"Enter the message:\n";
    char msg[100];
    cin.getline(msg,100); // メッセージを入力として受け取る
    int i, j, length, choice, key;
    cout << "Enter key: ";
    cin >> key; // 鍵を入力として受け取る
    length = strlen(msg);
    cout<<"Enter your choice \n1. Encryption \n2. Decryption \n";
    cin>>choice;
    if (choice==1) { // 暗号化
        char ch;
        for(int i = 0; msg[i] != '\0'; ++i) {
            ch = msg[i];
            // 小文字の暗号化
            if (ch >= 'a' && ch <= 'z') {
                ch = ch + key;
                if (ch > 'z') {
                    ch = ch - 'z' + 'a' - 1;
                }
                msg[i] = ch;
            }
            // 大文字の暗号化
            else if (ch >= 'A' && ch <= 'Z') {
                ch = ch + key;
                if (ch > 'Z') {
                    ch = ch - 'Z' + 'A' - 1;
                }
                msg[i] = ch;
            }
        }
        printf("Encrypted message: %s", msg);
    }
    else if (choice == 2) { // 復号化
        char ch;
        for(int i = 0; msg[i] != '\0'; ++i) {
            ch = msg[i];
            // 小文字の復号化
            if(ch >= 'a' && ch <= 'z') {
                ch = ch - key;
                if(ch < 'a') {
                    ch = ch + 'z' - 'a' + 1;
                }
                msg[i] = ch;
            }
            // 大文字の復号化
            else if(ch >= 'A' && ch <= 'Z') {
                ch = ch - key;
                if(ch < 'A') {
                    ch = ch + 'Z' - 'A' + 1;
                }
                msg[i] = ch;
            }
        }
        cout << "Decrypted message: " << msg;
    }
}

実行結果

【暗号化の場合】
Enter the message:
tutorial
Enter key: 3
Enter your choice
1. Encryption
2. Decryption
1
Encrypted message: wxwruldo

【復号化の場合】
Enter the message:
wxwruldo
Enter key: 3
Enter your choice
1. Encryption
2. Decryption
2
Decrypted message: tutorial

プログラムでは、まずメッセージと鍵を入力し、続いて「1(暗号化)」または「2(復号化)」を選択します。英小文字・英大文字のそれぞれに対してシフト処理を行い、アルファベットの範囲を超えた場合には先頭に折り返すことで、正しく変換できるようになっています。

補足:シーザー暗号の安全性について

シーザー暗号は仕組みが非常に単純な反面、安全性は低いことで知られています。アルファベットの場合、鍵となり得るシフト数は0〜25のわずか26通りしかないため、総当たり攻撃(ブルートフォース攻撃)ですべての鍵を試せば、必ず平文が得られてしまいます。

さらに、言語ごとの文字の出現頻度を利用した「頻度分析」によって鍵を推測することも容易です。このため、シーザー暗号が現代の実用的な通信に使われることはなく、主に暗号技術の仕組みを学ぶための教材として活用されています。

  1. 【C++】STLのset_symmetric_differenceで集合の対称差を実装するプログラム

    本記事では、C++の標準テンプレートライブラリ(STL)に含まれる set_symmetric_difference 関数を使って、2つの集合の「対称差」を求めるプログラムを紹介します。 対称差とは、2つの集合のうち「どちらか一方にだけ存在し、両方には存在しない」要素から構成される集合のことです。 主な集合演算の種類 和集合(Union):どちらか一方に含まれるすべての要素 積集合(Intersection):両方に共通して含まれる要素 対称差(Symmetric Difference / 排他的論理和 XOR):片方にのみ含まれる要素 差集合(Difference / 減算):一方から他方

  2. C++でグラフの隣接行列を実装する方法【サンプルコード付き解説】

    隣接行列とは グラフの隣接行列(Adjacency Matrix)とは、V×Vのサイズを持つ正方行列のことです。ここでVはグラフGの頂点数を表します。行列の行と列にはそれぞれ頂点が対応付けられ、頂点iから頂点jへの辺が存在する場合は、i行目・j列目の要素に1が格納されます(重み付きグラフの場合は、辺の重みなどの非ゼロの値が入ります)。辺が存在しない場合は0が格納されます。 なお、無向グラフの場合、辺は双方向につながりを持つため、隣接行列は必ず対称行列になります。つまり、adj[i][j]とadj[j][i]は常に同じ値となります。 隣接行列表現の計算量 空間計算量: 隣接行列にはO(V²)