シーザー暗号を実装するC++プログラム
シーザー暗号とは
シーザー暗号は、平文の各文字を別の文字に置き換えることで暗号文を作り出す「単一換字式暗号(モノアルファベット暗号)」の一種です。換字式暗号の中でも最も基本的でシンプルな方式とされています。
この暗号方式は、一般的に「シフト暗号」とも呼ばれます。その考え方は、各アルファベットを0〜25の範囲内の固定した数だけ「ずらした」別のアルファベットに置き換えるというものです。
この方式では、送信者と受信者があらかじめ「秘密のシフト数」を共有しておきます。この0〜25の間の数値が、暗号化の鍵(キー)として機能します。
特に「3文字ずらす」場合には、このシフト暗号を指して「シーザー暗号」と呼ぶことがあります。名称の由来は、古代ローマのユリウス・カエサルが軍事通信にこの方式を用いたことだと言われています。
暗号化・復号化のプロセス
平文の文字を暗号化するとき、送信者はスライド式の定規を平文の最初の文字列の下に当て、秘密のシフト数の分だけ左方向にスライドさせます。
そして、平文の文字を、その下に位置するスライド定規上の文字へと置き換えます。以下の図は、シフト数を3と合意した場合の処理結果を示したものです。この場合、平文「tutorial」は暗号文「wxwruldo」に変換されます。シフト数3のときの暗号用アルファベットは次の通りです。

暗号文を受け取った受信者も秘密のシフト数を知っているため、スライド定規を暗号文アルファベットの下に当て、今度は合意されたシフト数(ここでは3)の分だけ右方向にスライドさせます。
続いて、暗号文の文字を、その下のスライド定規上の平文の文字に置き換えます。これにより、暗号文「wxwruldo」は「tutorial」として復号されます。シフト数3で暗号化されたメッセージを復号するには、下図のように「−3」のシフトで平文用アルファベットを生成すればよいのです。

以上の処理を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通りしかないため、総当たり攻撃(ブルートフォース攻撃)ですべての鍵を試せば、必ず平文が得られてしまいます。
さらに、言語ごとの文字の出現頻度を利用した「頻度分析」によって鍵を推測することも容易です。このため、シーザー暗号が現代の実用的な通信に使われることはなく、主に暗号技術の仕組みを学ぶための教材として活用されています。
-
【C++】STLのset_symmetric_differenceで集合の対称差を実装するプログラム
本記事では、C++の標準テンプレートライブラリ(STL)に含まれる set_symmetric_difference 関数を使って、2つの集合の「対称差」を求めるプログラムを紹介します。 対称差とは、2つの集合のうち「どちらか一方にだけ存在し、両方には存在しない」要素から構成される集合のことです。 主な集合演算の種類 和集合(Union):どちらか一方に含まれるすべての要素 積集合(Intersection):両方に共通して含まれる要素 対称差(Symmetric Difference / 排他的論理和 XOR):片方にのみ含まれる要素 差集合(Difference / 減算):一方から他方
-
C++でグラフの隣接行列を実装する方法【サンプルコード付き解説】
隣接行列とは グラフの隣接行列(Adjacency Matrix)とは、V×Vのサイズを持つ正方行列のことです。ここでVはグラフGの頂点数を表します。行列の行と列にはそれぞれ頂点が対応付けられ、頂点iから頂点jへの辺が存在する場合は、i行目・j列目の要素に1が格納されます(重み付きグラフの場合は、辺の重みなどの非ゼロの値が入ります)。辺が存在しない場合は0が格納されます。 なお、無向グラフの場合、辺は双方向につながりを持つため、隣接行列は必ず対称行列になります。つまり、adj[i][j]とadj[j][i]は常に同じ値となります。 隣接行列表現の計算量 空間計算量: 隣接行列にはO(V²)