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

ヒル暗号をC++で実装する方法:暗号化と復号の仕組みをサンプルコード付きで解説

ヒル暗号(Hill Cipher)は、線形代数を基礎とする多表字換暗号(polygraphic substitution cipher)の一種で、暗号理論における古典的な手法のひとつです。複数の文字をブロックとしてまとめて変換するため、単純な換字暗号よりも高い安全性を持ちます。

暗号化:鍵文字列と平文(メッセージ)をそれぞれ行列形式で表現し、両者を乗算した結果に対して mod 26 を適用することで暗号文を生成します。後から復号を行うためには、鍵行列が逆行列を持つことが前提条件となります。

復号:暗号化に使用した鍵行列の逆行列を暗号文行列に乗算し、mod 26 を計算することで元のメッセージを復元します。

なお、mod 26 を用いるのは、アルファベットの大文字 A〜Z の26文字に対応させるためです。また、n×n の鍵行列を使うことで n 文字ずつをひとつのブロックとして暗号化でき、以下の例では 3×3 行列によって 3 文字単位で処理を行います。

具体例

鍵行列

1 0 1
2 4 0
3 5 6

メッセージ「ABC」を行列形式で表すと、次のようになります。

0
1
2

暗号化の計算

上記の2つの行列を乗算すると、次の結果が得られます。

2
4
17

これが暗号文「CER」に対応します。

復号の計算

鍵行列の逆行列は以下の通りです。

1.09091 0.227273 -0.181818
-0.545455 0.136364 0.0909091
-0.0909091 -0.227273 0.181818

この逆行列を暗号文行列に乗算すると、

0
1
2

となり、元のメッセージ「ABC」が正しく復元されていることが確認できます。

以下では、この一連の処理を実装したC++プログラムを紹介します。

アルゴリズム

開始
関数 getKeyMatrix()
  i = 0 ~ 2 について
    j = 0 ~ 2 について
      行列 a[i][j] の要素を入力として受け取る
      m[i][j] = a[i][j]
    (繰り返し終了)
  (繰り返し終了)
  メッセージ文字列をユーザー入力として受け取る
  i = 0 ~ 2 について
    msg[i][0] = mes[i] - 65
  (繰り返し終了)
終了

開始
関数 encrypt()
  i = 0 ~ 2、j = 0、k = 0 ~ 2 について
    en[i][j] = en[i][j] + a[i][k] × msg[k][j]
  乗算結果の各要素に mod 26 を適用し、暗号文を出力する
終了

開始
関数 decrypt()
  inversematrix() 関数を呼び出す
  i = 0 ~ 2、j = 0、k = 0 ~ 2 について
    de[i][j] = de[i][j] + b[i][k] × en[k][j]
  乗算結果に mod 26 を適用して元のメッセージを取得する
終了

C++による実装例

#include<iostream>
#include<math.h>
using namespace std;
float en[3][1], de[3][1], a[3][3], b[3][3], msg[3][1], m[3][3];
void getKeyMatrix() { // ユーザーから鍵行列とメッセージを入力
   int i, j;
   char mes[3];
   cout<<"Enter 3x3 matrix for key (should have inverse):\n";
   for(i = 0; i < 3; i++)
   for(j = 0; j < 3; j++) {
      cin>>a[i][j];
      m[i][j] = a[i][j];
   }
   cout<<"\nEnter a string of 3 letter(use A through Z): ";
   cin>>mes;
   for(i = 0; i < 3; i++)
   msg[i][0] = mes[i] - 65;
}
void encrypt() { // メッセージを暗号化する
   int i, j, k;
   for(i = 0; i < 3; i++)
   for(j = 0; j < 1; j++)
   for(k = 0; k < 3; k++)
   en[i][j] = en[i][j] + a[i][k] * msg[k][j];
   cout<<"\nEncrypted string is: ";
   for(i = 0; i < 3; i++)
   cout<<(char)(fmod(en[i][0], 26) + 65); // 乗算結果の各要素にmod 26を適用
}
void inversematrix() { // 鍵行列の逆行列を求める
   int i, j, k;
   float p, q;
   for(i = 0; i < 3; i++)
   for(j = 0; j < 3; j++) {
      if(i == j)
         b[i][j]=1;
      else
         b[i][j]=0;
   }
   for(k = 0; k < 3; k++) {
      for(i = 0; i < 3; i++) {
         p = m[i][k];
         q = m[k][k];
         for(j = 0; j < 3; j++) {
            if(i != k) {
               m[i][j] = m[i][j]*q - p*m[k][j];
               b[i][j] = b[i][j]*q - p*b[k][j];
            }
         }
      }
   }
   for(i = 0; i < 3; i++)
   for(j = 0; j < 3; j++)
   b[i][j] = b[i][j] / m[i][i];
   cout<<"\n\nInverse Matrix is:\n";
   for(i = 0; i < 3; i++) {
      for(j = 0; j < 3; j++)
      cout<<b[i][j]<<" ";
      cout<<"\n";
   }
}
void decrypt() { // メッセージを復号する
   int i, j, k;
   inversematrix();
   for(i = 0; i < 3; i++)
   for(j = 0; j < 1; j++)
   for(k = 0; k < 3; k++)
   de[i][j] = de[i][j] + b[i][k] * en[k][j];
   cout<<"\nDecrypted string is: ";
   for(i = 0; i < 3; i++)
   cout<<(char)(fmod(de[i][0], 26) + 65); // mod 26を適用して元のメッセージを取得
   cout<<"\n";
}
int main() {
   getKeyMatrix();
   encrypt();
   decrypt();
}

実行結果

Enter 3x3 matrix for key (should have inverse):
1
0
1
2
4
0
3
5
6

Enter a string of 3 letter(use A through Z): ABC

Encrypted string is: CER

Inverse Matrix is:
1.09091 0.227273 -0.181818
-0.545455 0.136364 0.0909091
-0.0909091 -0.227273 0.181818

Decrypted string is: ABC
  1. C++でAVL木(AVLツリー)を実装する方法:回転操作とサンプルコードを徹底解説

    AVL木とは AVL木(AVL Tree)は、自己平衡型二分探索木(Self-balancing Binary Search Tree)の一種です。すべてのノードにおいて、左部分木と右部分木の高さの差が「1以下」に保たれるという性質を持っています。この平衡条件により、木が片側に偏って成長することを防ぎ、検索・挿入・削除といった操作を常に効率的(O(log n))に行うことができます。 木の回転(Tree Rotation)とは 木の回転とは、要素の順序(ソート順)を崩すことなく木の構造を変更する操作のことです。あるノードを一段上へ移動させ、別のノードを一段下へ移動させることで実現されます。 回

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

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