LoginSignup
1
2

More than 3 years have passed since last update.

HackerzLab.博多 Vol.21 RSA公開鍵暗号化方式の実装ハンズオン

Last updated at Posted at 2019-04-23

この記事は、

2019/05/05(Sun) HackerzLab.博多 Vol.21
『RSA公開鍵暗号化方式の実装ハンズオン』

の資料です。

1. 作業用プロジェクトのダウンロード

ハンズオン開始用プロジェクト(ファイル群)をダウンロードします。

gitがインストールされていない場合は、各自でインストールするか、

もしくはハンズオン当日の共有フォルダから開始用プロジェクト(フォルダ)を
コピーしてください(詳細は当日説明します)。

$ git clone https://github.com/NobuyukiInoue/Example_RSA_Work/

作業ディレクトリに移動します。

$ cd Example_RSA_Work

カレントディレクトリのパスを確認しておきます。

s19@ubuntu1804:~/Example_RSA$ pwd
/home/s??/Example_RSA

2. ディレクトリ構成

ディレクトリ構成は以下の通りです。
必要なファイルはすべて用意してあります。

入力が未完全なプログラムがあるので、完成例を見ながら、
各自で足りない部分を入力して完成させていきましょう。

入力が必要な行には、目印として行頭に#の文字を配置しています。

3-1~3-5 のファイルは、検証用スクリプトの実行時に必要となりますので、

入力漏れや文字の間違いがないように、
じっくりと完成後のソースファイルと見比べながら、正確に入力するようにしてください。

ディレクトリ構成
Example_RSA
├─rsa_test.py  ..................... 3-0
├─rsa_main_mode_txt.py  ............ 3-1
├─rsa_main_mode_bin.py  ............ 3-2
├─print_FileHash.py ................ 3-3
├─rsa_trial_division.py  ........... 4-4
│
├─my_modules
│  ├─getch.py  ..................... 3-4
│  └─rsa.py  ....................... 3-5
│
├─TestScripts_mode_txt  ............ 4-1
│  ├─bash  ......................... 4-1-A
│  │ ├─original_utf8.txt
│  │ ├─repeated_main_mode_txt.sh
│  │ └─test_mode_txt.sh
│  │
│  └─ps1  .......................... 4-1-B
│    ├─original_sjis.txt
│    ├─repeated_main_mode_txt.ps1
│    └─test_mode_txt.ps1
│
└─TestScripts_mode_bin  ............ 4-2
   ├─bash  ......................... 4-2-A
   │ ├─original.txt
   │ ├─original.jpg
   │ ├─repeated_main_mode_bin.sh
   │ └─test_mode_bin.sh
   │
   └─ps1  .......................... 4-2-B
     ├─original.txt
     ├─original.jpg
     ├─repeated_main_mode_bin.ps1
     └─test_mode_bin.ps1

3. プログラムの作成(入力)

2つのメインプログラムがあります。

3-0. rsa_test.py

鍵ペアの生成(ファイルには出力しない)、元テキストの暗号化、復号のみを行うプログラムです。
3-5. my_modules/rsa.py の入力が終わったら、動作テストとして実行してみることにします。

3-1. rsa_main_mode_txt.py

テキスト形式のみに対応した暗号化/復号処理プログラムです。
暗号化後の結果、復号後の結果は標準出力に表示されます。

結果をファイルに保存したい場合は、リダイレクトを利用してください。

今回のハンズオンでは、rsa_main_mode_txt.py の説明は割愛いたします。

3-2. rsa_main_mode_bin.py

テキストファイルとバイナリファイルの両方に対応した暗号化/復号処理プログラムです。
暗号化後の結果、復号後の結果は、引数で指定したファイルに書き出されます。

3-3. print_FileHash.py

ファイルのハッシュ値を算出するプログラムです。
暗号化前のファイルとと暗号化/復号後のファイルの内容が、一致しているか調べる場合に使用します。

3-4. my_modules/getch.py

キーボードからの文字の読み込みを行う処理をまとめたライブラリです。
ファイルの上書き保存の確認時などに使用します。

すでに完成済みを配布していますので、編集は不要です。

3-5. my_modules/rsa.py

素数の生成、RSA公開鍵暗号化方式による鍵ペアの生成、暗号化、復号などの処理を関数化したライブラリです。

鍵の生成、暗号化、復号の関数は、下記の記事を参考にさせていただいております。

Python で公開鍵暗号アルゴリズム RSA を実装してみる
https://qiita.com/QUANON/items/e7b181dd08f2f0b4fdbe

4. 動作テスト

入力が終わったら、動作テストとして 3-0.で作成した rsa_test.py を実行してみます。

pythonrsa_test.py を実行してみましょう。

$ python rsa_test.py
p = 2551, q = 2207
秘密鍵:(E = 7, N = 5630057)
公開鍵:(D = 2410843, N = 5630057)
平文:この文字列を暗号化/復号化するよ♪
暗号文:004aeb7c00172f07001bf76d0011d53a0034dd090042153a00430f3200084a7b00435a8b001df9180016383700084a7b00435a8b0009e53500195b20002641cd002a999e
平文:この文字列を暗号化/復号化するよ♪
Success.

2つの平文の内容が一致しており、実行結果としてSuccess.と表示されました。
暗号化/復号に成功しているようです。

4-1. 検証用スクリプトによる動作テスト(rsa_main_mode_txt.py用)

rsa_main_mode_txt.py の検証用スクリプト群です。
bash版PowerShell版の2つがあります。

macOS/Linuxを使用している方はbash版を、
Windowsを利用している方はPowerShell版を使用してください。

  • 4-1-A. TestScripts_mode_txt/bash ... bash版
  • 4-1-B. TestScripts_mode_txt/ps1 ..... PowerShell版

今回のハンズオンでは、4-1.のスクリプト群による検証は割愛します。

4-2. 検証用スクリプトによる動作テスト(rsa_main_mode_bin.py用)

rsa_main_mode_bin.py の検証用スクリプト群です。
bash版とPowerShell版の2つがあります。

macOS/Linuxを使用している方はbash版を、
Windowsを利用している方はPowerShell版を使用してください。

  • 4-2-A. TestScripts_mode_bin/bash ... bash版
  • 4-2-B. TestScripts_mode_bin/ps1 ..... PowerShell版

4-2-A. TestScripts_mode_bin/bash

  • 鍵ペアの生成、公開鍵による暗号化、秘密鍵による復号処理、元ファイルとの比較
  • 鍵ペアの生成、秘密鍵による暗号化、公開鍵による復号処理、元ファイルとの比較

をそれぞれ10回づつ実行する検証用スクリプト群(bash版)です。

  • カレントディレクトリを変更
$ cd TestScripts_mode_bin/bash
  • カレントディレクトリのパスを確認
$ pwd
/home/s??/Example_RSA_Work/TestScripts_mode_bin/bash
  • ファイル一覧の確認
$ ls -al
合計 68
drwxr-xr-x 2 sxx students  4096  4月 23 20:54 .
drwxr-xr-x 4 sxx students  4096  4月 23 20:54 ..
-rw-r--r-- 1 sxx students 46948  4月 23 20:54 original.jpg
-rw-r--r-- 1 sxx students    32  4月 23 20:54 original.txt
-rw-r--r-- 1 sxx students   488  4月 23 20:54 repeated_main_mode_bin.sh
-rw-r--r-- 1 sxx students  3654  4月 23 20:54 test_mode_bin.sh
  • 検証用スクリプトの実行
$ ./repeated_main_mode_bin.sh
...
...
args = ./test_mode_bin.sh public.key private.key ./original.jpg ./test.bin ./test.jpg 0
Execute: python ../../rsa_main_mode_bin.py create_key
Execute: python ../../rsa_main_mode_bin.py encrypt ./original.jpg ./test.bin private.key
Execute: python ../../rsa_main_mode_bin.py decrypt ./test.bin ./test.jpg public.key
public.key          :3,4512649
private.key         :751361,4512649
./original.jpg      :MD5 : c9dc1e2b3135d0f76203de5820b840f5
./test.jpg          :MD5 : c9dc1e2b3135d0f76203de5820b840f5
<<Success>>

確認が終わったら、カレントディレクトリをExample_RSA_Workディレクトリに戻しておきます。

$ cd ../..
$ pwd
/home/s??/Example_RSA_Work

4-2-B. TestScripts_mode_bin/ps1

  • 鍵ペアの生成、公開鍵による暗号化、秘密鍵による復号処理、元ファイルとの比較
  • 鍵ペアの生成、秘密鍵による暗号化、公開鍵による復号処理、元ファイルとの比較

をそれぞれ10回づつ実行する検証用スクリプト群(PowerShell版)です。

  • カレントディレクトリを変更
> cd TestScripts_mode_bin/ps1
  • ファイル一覧の確認
> Get-ChildItem
    ディレクトリ: C:\....\Example_RSA_Work\TestScripts_mode_bin\ps1

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2018/07/02     22:02          46948 original.jpg
-ar---       2019/04/14      0:51             34 original.txt
-a----       2019/04/21     20:55            571 repeated_main_mode_bin.ps1
-a----       2019/04/21     20:52           4309 test_mode_bin.ps1
  • 検証用スクリプトの実行
> ./repeated_main_mode_bin.ps1
...
...
args = test_mode_bin.ps1 ./public.key ./private.key ./original.jpg ./test.bin ./test.jpg False
Execute: python ../../rsa_main_mode_bin.py create_key
Execute: python ../../rsa_main_mode_bin.py encrypt ./original.jpg ./test.bin ./private.key
Execute: python ../../rsa_main_mode_bin.py decrypt ./test.bin ./test.jpg ./public.key
./public.key         : 7,4755749
./private.key        : 678763,4755749
./original.jpg       MD5 : 351efe5e4d33d7ca16c86b3137c78011
./test.jpg           MD5 : 351efe5e4d33d7ca16c86b3137c78011
<<Sucess>>

確認が終わったら、カレントディレクトリをExample_RSA_Workディレクトリに戻しておきます。

> cd ../..
> pwd
Path
----
C:\Users\.....\Example_RSA_Work

4-3. 公開鍵と秘密鍵の生成と暗号化/復号の仕組み

公開鍵と秘密鍵の生成と暗号化/復号の仕組みを少しだけ解説します。

4-2-B. の検証用スクリプトの実行結果の例を見ると、
public.keyとprivate.keyの値が以下のように出力されていました。

./public.key         : 7,4755749
./private.key        : 678763,4755749

public.key の最初の値 7 は、公開鍵を使ったべき乗計算で使用する変数Eを表しています。

次に続く 4755749 は、とある2つの素数(pとq)の積Nです。

(公開鍵の変数Eは、φ(n)=(p-1)(q-1))未満で互いに素な正の整数です。一般的には2^16 + 1 = 65537の固定された値がよく使われますが、今回は毎回異なる値を生成しています。)

public.key には、
E = 7, N = 4755749
という値が保存されていたことになります。

private.key の最初の値 678763 は、秘密鍵を使ったべき乗計算で使用する変数Dを表しています。

次に続く 4755749 は、とある2つの素数(pとq)の積Nであり、公開鍵のNと同じ値を使っています。

(秘密鍵の変数Dは E*D ≡ 1 (mod N) の式を変形した E*D - N*x = gcd(E,N) = 1を、拡張されたユークリッドの互除法で解いて求めた値です。)

private.key には、
D = 678763, N = 4755749
という値が保存されていたことになります。

ちなみに、とある2つの素数(pとq)ですが、どんな値なのでしょうか?

この値がバレてしまうと、簡単に何度でも(公開鍵と)秘密鍵を再生成することができるので、
今回のプログラムでは、乱数を使って2つの素数を選んだあと、鍵ペアの生成後に保存せずに破棄しています。

ですので、プログラムを書いた私も解らなくなっています。

興味があればNを素因数分解して求めてみてください(笑)

今回のプログラムでは公開鍵のEおよびNは小さめの値になっているので、
強度は高くありません。(実はかなり低い)

詳しくは、4-4. 鍵の強度で取り扱います。

とある2つの素数(p, q)の話はここまでにするとして、、、、

それでは、pythonをインタプリタ形式で起動して、これらの値を使って暗号化と復号の実験をしてみましょう。

$ python
Python 3.6.5 (default, May  3 2018, 10:08:28)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

pythonが起動したら、変数Nに、とある2つの素数の積である4755749を代入しておきます。


>>> N = 4755749

公開鍵で使用する変数Eに7を代入します。

>>> E = 7

公開鍵で使用する変数Dに678763を代入します。

>>> D = 678763

暗号化は、元の値をE乗したあと、Nで割って余りを得るという計算で行うことができます。
pythonだと、pow(元の値, E, N)という式になります。

暗号化したい元の値999として、公開鍵で暗号化する演算を行ってみましょう。

>>> pow(999, E, N)
1878484

1878484という結果が返されました。
この数値が暗号化後の値です。

次に、秘密鍵による復号を行ってみます。

復号は、暗号化後の値をD乗したあと、Nで割って余りを得るという計算で行うことができます。
pythonだと、pow(暗号化後の値, D, N)という式になります。

暗号化後の値を、さきほどの計算結果である1878484として、秘密鍵で復号する演算を行ってみましょう。

>>> pow(1878484, D, N)
999

あら不思議!!!
元の値である999が返されました。

暗号化と復号の処理が成功したことになります。

では、今度は逆に、秘密鍵での暗号化、公開鍵での復号を行ってみましょう。

先に、秘密鍵での暗号化を行ってみます。

>>> pow(999, D, N)
3065016

続いて、公開鍵での復号を行ってみます。

>>> pow(3065016, E, N)
999

こちらの処理でも、元の値が返された様子が解ります。

公開鍵と秘密鍵はペアとして使用する不思議な値(笑)の組み合わせで、
この組み合わせを使うと、

  • 公開鍵で暗号化したあと、秘密鍵で復号
  • 秘密鍵で暗号化したあと、公開鍵で復号

のどちらの計算でも、元の値を復元することができるのです。

補足

起動していたpythonですが、

Windows ........ CTRL + Z
macOS/Linux .... CTRL + D

を入力して終了させておいてください。

4-4. 鍵の強度

4-3. 公開鍵と秘密鍵の生成と暗号化/復号の仕組み にて、
とある2つの素数の組み合わせの積Nの話題を出しましたが、

実際にプログラムを組んで素因数分解を行うと、どれくらいの時間がかかるのでしょうか?

与えられた数値を素因数分解し、
2つの素数が見つかった場合には鍵ペアを生成する
プログラムも用意しています。

実行方法は以下の通りです。

python rsa_trial_division.py 素因数分解したい値

ちょっと実験してみましょう。

$ python rsa_trial_division.py 4755749
4755749 < pow(2, 23)
[1879, 2531]

Do you want to create a key? (Y/N):
Public key filename [rsa_public.key]:recalc_public.key      <--- 再生成する公開鍵のファイル名
Private key filename [rsa_private.key]:recalc_private.key   <--- 再生成する秘密鍵のファイル名

一瞬で計算が終わりました。
素因数分解の結果として、2つの数値 [1879, 2531] が出力されました。

4755749 < pow(2, 23)という結果も表示されていますが、
これは 47557492の23乗 未満だったことを表しています。
(すなわち、鍵長は23ビットだった)

この2つの値が、とある2つの素数(pとq) なのでしょうか?

電卓もしくはPythonなどで 1879*2531 を再計算して確かめると、
4755749になります。

ちなみに、18792531rsa_trial_division.py の引数で与えて
素因数分解してみると、

それ以上は素因数分解できず、2つの値とも素数だということが解ります。

$ python rsa_trial_division.py 1879
1879 < pow(2, 11)
1879 is a prime number.
$ python rsa_trial_division.py 2531
2531 < pow(2, 12)
2531 is a prime number.

プログラムは、素因数分解の結果が2つの値だけだった場合には、
鍵ペアも生成してくれています。

再計算して生成した鍵ファイルを確認してみましょう。
ますは ls -alコマンド の実行結果から。

$ ls -al
...
...
-rw-r--r-- 1 s19 students   14  4月 23 21:42 recalc_private.key <--- 4-4. 再計算して生成した秘密鍵ファイル
-rw-r--r-- 1 s19 students    9  4月 23 21:42 recalc_public.key  <--- 4-4. 再計算して生成した公開鍵ファイル

公開鍵ファイル秘密鍵ファイルともに生成されているようです。
しかも、ファイルのサイズも見覚えがありますね。

catコマンドでファイルの内容を表示してみます。

$ cat recalc_public.key
7,4755749
$ cat recalc_private.key
678763,4755749

「おぉぉぉ。。。。!!!」

4-3. 公開鍵と秘密鍵の生成と暗号化/復号の仕組み で調べた E, D, N と同じ値が表示されました。

公開鍵の変数Nから、あっというまに公開鍵と秘密鍵が再生成できてしまった...ww

「どうしよう♪♪♪♪」
「HackerzLab.博多 ハンズオン用 Example_RSA の脆弱性を発見してしまった...!!」

というやつでしょうか(笑)

ちょっとだけハッカーになってしまった気分ですね。

それはさておき、

さきほどの素因数分解用プログラム rsa_trial_division.py に与える数値を大きくしていくと、
素因数分解にかかる時間も増えていきます。

一桁ずつ増やしていくと、どれくらい処理時間も増えていくのか、体験してみてください。

推奨される鍵長

今回のハンズオン用のプログラムでは、セキュリティ強度よりもプログラムの簡潔さや理解のしやすさ、処理の軽快さを重視しているため、鍵長は21~23ビット程度に抑えています。

2004年の時点でも、インターネットで公募した数多くのPCを用いると512ビット程度の数なら素因数分解できていました。

現在では、RSA暗号に使用する とある2つの素数の積N1024-4096ビット(10進数で300-1000桁程度)にすることが推奨されています。

鍵長の推奨値は、PCの処理速度向上に伴い、今後も大きくなり続けることは間違いありません。

Example_RSA で鍵長を大きくするには?

Example_RSAでも、プログラムを修正すれば鍵長を大きくすることができます。

のどこを修正すれば良いのか、プログラムをよく読んで考えてみましょう。

PEM/DERファイルについて

暗号化 – .pem、.cer、および.derの違いは何ですか?
https://codeday.me/jp/qa/20190130/213979.html

RSA暗号とPEM/DERの構造
https://www.sambaiz.net/article/135/

5. 暗号化データの送付とディジタル署名による改ざん防止の実験

完成したプログラムを使って、暗号化データの送付とディジタル署名による検証の実験を行ってみます。

公開鍵暗号化方式による暗号化データの送信や、ディジタル署名による検証の概念をまとめると、以下の図のようになります。

今回のハンズオンでは、以下の流れで作業を進めていきます。

  • 事前準備
    5-1. 実験用鍵ペアの生成
    5-2. 公開鍵の配布(共有フォルダへの配置)

  • 送信者側の作業
    5-3. 暗号化前の元ファイルの作成
    5-4. 送りたいファイルを受信者の公開鍵で暗号化する
    5-5. 暗号化したファイルをハッシュ化し、メッセージダイジェストを生成する
    5-6. 得られたメッセージダイジェストを送信者の秘密鍵で暗号化する
    5-7. 暗号化したファイルとディジタル署名を受信者側に送る

  • 受信者側の作業
    5-8. 暗号化されたファイルとディジタル署名を受け取る
    5-9. 受け取ったディジタル署名を送信者の公開鍵で復号し、暗号化されたファイルをハッシュ化して得られるメッセージダイジェストと比較する
    5-10. 暗号化されたファイルを受信者の秘密鍵で復号し、元のデータを得る

5-1. 実験用鍵ペアの生成

カレントディレクトリを Example_RSA_Work を展開したディレクトリに変更します。

$ cd ~/Example_RSA_Work

鍵ペアを生成します。
ただし鍵のファイル名は、ほかの参加者とのファイル名の重複を避けるため、

  • 公開鍵ファイル: s??_public.key
  • 秘密鍵ファイル: s??_private.key

としてください。 s?? は各自に割り当てられた番号です。

s19@ubuntu1804:~/Example_RSA$ python rsa_main_mode_bin.py create_key
Public key filename [rsa_public.key]:s19_public.key    <--- 自分用の公開鍵のファイル名を入力
Private key filename [rsa_private.key]:s19_private.key <--- 自分用の秘密鍵のファイル名を入力
Create Keys done.

作成された鍵ファイルをlsコマンドで確認します。

s19@ubuntu1804:~/Example_RSA$ ls -al
合計 80
drwxr-xr-x 9 s19 students 4096  4月 23 21:42 .
drwxr-xr-x 6 s19 students 4096  4月 23 21:08 ..
drwxr-xr-x 8 s19 students 4096  4月 23 21:08 .git
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 .vscode
-rw-r--r-- 1 s19 students 8525  4月 23 21:08 README.md
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_bin
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_txt
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 base64_work
drwxr-xr-x 3 s19 students 4096  4月 23 21:08 my_modules
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 org
-rw-r--r-- 1 s19 students  958  4月 23 21:08 print_FileHash.py
-rw-r--r-- 1 s19 students 4395  4月 23 21:08 rsa_main_mode_bin.py
-rw-r--r-- 1 s19 students 4868  4月 23 21:08 rsa_main_mode_txt.py
-rw-r--r-- 1 s19 students 1394  4月 23 21:08 rsa_test.py
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key <--- 5-1. 自分用の秘密鍵ファイル
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key  <--- 5-1. 自分用の公開鍵ファイル

5-2. 公開鍵の配布(共有フォルダへの配置)

参加者の公開鍵および電子メールアドレスをメンバー間で共有(公開)するため、
講師側が指示した公開鍵配置用共有フォルダに公開鍵を配置します。

☆公開鍵配置用共有フォルダ案
\\ubuntu1804\share

配置が終わったら、暗号化データの送信相手の公開鍵を
Example_RSA_Workの作業ディレクトリ(~/Example_RSA)にコピーしておきます。

作業の詳細は、当日、会場にて説明いたします。

s19さんがs00さんの公開鍵を作業ディレクトリ(~/Example_RSA_Work)にコピーして配置した場合、
下記のようなファイル配置になります。

s19@ubuntu1804:~/Example_RSA$ ls -al
合計 80
drwxr-xr-x 9 s19 students 4096  4月 23 21:42 .
drwxr-xr-x 6 s19 students 4096  4月 23 21:08 ..
drwxr-xr-x 8 s19 students 4096  4月 23 21:08 .git
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 .vscode
-rw-r--r-- 1 s19 students 8525  4月 23 21:08 README.md
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_bin
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_txt
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 base64_work
drwxr-xr-x 3 s19 students 4096  4月 23 21:08 my_modules
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 org
-rw-r--r-- 1 s19 students  958  4月 23 21:08 print_FileHash.py
-rw-r--r-- 1 s19 students 4395  4月 23 21:08 rsa_main_mode_bin.py
-rw-r--r-- 1 s19 students 4868  4月 23 21:08 rsa_main_mode_txt.py
-rw-r--r-- 1 s19 students 1394  4月 23 21:08 rsa_test.py
-rw-r--r-- 1 s19 students    9  4月 23 21:40 s00_public.key  <--- 5-2. 送信相手の公開鍵ファイル
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key <--- 5-1. 自分用の秘密鍵ファイル
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key  <--- 5-1. 自分用の公開鍵ファイル

5-3. 暗号化前の元ファイルの作成

暗号化データの送付とディジタル署名(メッセージダイジェスト)の確認の実験として
暗号化前の元ファイルを作成しておきます。

WindowsやmacOSなどのGUI操作で作成・入力してかまいません。

ファイル名は、s??_data.txt とします。
(s?? は各自に割り当てられた番号です。)

今回の環境ではWindows/macOS/Linuxユーザーが混在しているため、
文字コードを(macOS/Linuxのデフォルト値に)統一しておくことにします。

一般的なテキストエディタでは、ファイルに保存する際に、文字コードと改行コードを指定する機能があります。
各自で調べてみてください。

文字コード 改行コード
UTF8 LFのみ
s??_data.txt
お世話になっております。
s??(○○)です。

メッセージを暗号化して送ります。
読めるかなぁぁ??

lsコマンドでファイルの一覧を確認しておきます。

s19@ubuntu1804:~/Example_RSA_Work$ ls -al
合計 84
drwxr-xr-x 9 s19 students 4096  4月 23 21:49 .
drwxr-xr-x 6 s19 students 4096  4月 23 21:08 ..
drwxr-xr-x 8 s19 students 4096  4月 23 21:08 .git
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 .vscode
-rw-r--r-- 1 s19 students 8525  4月 23 21:08 README.md
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_bin
drwxr-xr-x 4 s19 students 4096  4月 23 21:08 TestScripts_mode_txt
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 base64_work
drwxr-xr-x 3 s19 students 4096  4月 23 21:08 my_modules
drwxr-xr-x 2 s19 students 4096  4月 23 21:08 org
-rw-r--r-- 1 s19 students  958  4月 23 21:08 print_FileHash.py
-rw-r--r-- 1 s19 students 4395  4月 23 21:08 rsa_main_mode_bin.py
-rw-r--r-- 1 s19 students 4868  4月 23 21:08 rsa_main_mode_txt.py
-rw-r--r-- 1 s19 students 1394  4月 23 21:08 rsa_test.py
-rw-r--r-- 1 s19 students    9  4月 23 21:40 s00_public.key  <--- 5-2. 送信相手の公開鍵ファイル
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key
-rw-r--r-- 1 s19 students  140  4月 23 21:52 s19_data.txt    <--- 5-3. 暗号化前元ファイル

5-4. 送りたいファイルを受信者の公開鍵で暗号化する

5-2.で取得した 送信相手の公開鍵 で、元ファイル(s??_data.txt)を暗号化します。

暗号化後のファイル名は、(送信相手毎に異なる公開鍵を使用するため)、
s??_data_to_sXX.bin とします。
s??は送信者(自分)の番号、sXXは送信相手の番号です。)

rsa_main_mode.py の引数は以下のようになります。

python rsa_main_mode_bin.py encrypt 元ファイル名 暗号化後のファイル名 送信相手の公開鍵ファイル名

公開鍵ファイルは、送信相手の公開鍵を指定してください。
s19さんがs00さん宛に送信する場合、以下のようになります。

s19@ubuntu1804:~/Example_RSA_Work$ python rsa_main_mode_bin.py encrypt s19_data.txt s19_data_to_s00.bin s00_public.key

暗号化が終わったら、暗号化後のファイルが生成されているか確認しておきます。

s19@ubuntu1804:~/Example_RSA_Work$ ls -al
...
...
-rw-r--r-- 1 s19 students    9  4月 23 21:40 s00_public.key       <--- 5-2. 送信相手の公開鍵ファイル
-rw-r--r-- 1 s19 students  140  4月 23 21:52 s19_data.txt         <--- 5-3. 暗号化前元ファイル
-rw-r--r-- 1 s19 students 1120  4月 23 21:53 s19_data_to_s00.bin  <--- 5-4. s00の公開鍵で暗号化したファイル
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key

5-5. メッセージダイジェスト(送信する暗号化データのハッシュ値)の生成

送信データ(暗号化後のファイル)メッセージダイジェスト(送信する暗号化データのハッシュ値)を出力します。

print_FileHash.py の引数として、送信データ(暗号化後のファイル)MD5を指定して実行します。
出力されるハッシュ値は、暗号化されたデータ毎に違う結果になります。

s19@ubuntu1804:~/Example_RSA_Work$ python print_FileHash.py s19_data_to_s00.bin MD5
MD5 : ce6596060ff8e49bd971c0f13191e2c4

出力結果は、下記のように標準出力を、ファイルにリダイレクトするか、またはOut-Fileコマンドレットでファイルに書き出すと良いでしょう。

> python .\print_FileHash.py .\s19_data_to_s00.bin MD5 | Out-File -Encoding Ascii  s19_data_to_s00.MD5.unicode

または、

> python .\print_FileHash.py .\s19_data_to_s00.bin MD5 > s19_data_to_s00.MD5.unicode

WindowsのPowerShellでは、リダイレクトで出力した場合、出力後のファイルの文字コードがUNICODEになります。
(Windowsのコマンド プロンプト上でのリダイレクトはSJISです。)

送信者側と受信者側で文字コード(改行コード)が一致していないと、
復号後の結果が変わってしまいますので、

Windowsユーザーの方は、この後の作業で、文字コードの変換を行います。

s19@ubuntu1804:~/Example_RSA_Work$ python print_FileHash.py s19_data_to_s00.bin MD5 > s19_data_to_s00.MD5

正しくファイルに出力されているか、テキストエディタまたはcatコマンドで確認します。

Windowsユーザーの方は、テキストエディタで開いたあと、
UTF8 & LFのみ を指定して上書き保存しておいてください。

s19@ubuntu1804:~/Example_RSA_Work$ cat s19_data_to_s00.MD5
MD5 : ce6596060ff8e49bd971c0f13191e2c4
s19@ubuntu1804:~/Example_RSA_Work$ ls -al
...
...
-rw-r--r-- 1 s19 students    9  4月 23 21:40 s00_public.key       <--- 5-2. 送信相手の公開鍵ファイル
-rw-r--r-- 1 s19 students  140  4月 23 21:52 s19_data.txt         <--- 5-3. 暗号化前元ファイル
-rw-r--r-- 1 s19 students   39  4月 23 21:54 s19_data_to_s00.MD5  <--- 5-5. メッセージダイジェスト
-rw-r--r-- 1 s19 students 1120  4月 23 21:53 s19_data_to_s00.bin  <--- 5-4. s00の公開鍵で暗号化したファイル
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key

補足)PowerShellのリダイレクト結果(Unicode & CRLF)をコマンドでUTF8 & LFに変換する

PowerShellのリダイレクト結果(Unicode & CRLF)を、PowerShellのコマンドでコード変換することもできます。

手順は以下の通りです。

①.ハッシュ出力をリダイレクトで作業ファイル(s19_data_to_s00.MD5.unicode)に出力します。

> python .\print_FileHash.py .\s19_data_to_s00.bin MD5 > s19_data_to_s00.MD5.unicode

②.Get-ContentコマンドおよびSet-Contentコマンドでコードを変換し、ファイルに再出力します。

> (Get-Content -Path "s19_data_to_s00.MD5.unicode" -Encoding Unicode) -join "`n" `
    | % { [Text.Encoding]::UTF8.GetBytes($_) } `
    | Set-Content -Path "s19_data_to_s00.MD5" -Encoding Byte

③.MD5ファイルが作成されているか確認します。
(念のため、テキストエディタでも保存されているコードを確認してください。)

> Get-Content .\s19_data_to_s00.MD5

④.作業ファイル(s19_data_to_s00.MD5.unicode)を削除します。

> rm s19_data_to_s00.MD5.unicode

5-6. ディジタル署名の作成

5-5.で作成したハッシュ値の出力結果(s??_data_to_sXX.MD5)から、
送信者(自分)の秘密鍵で暗号化したディジタル署名を作成します。

生成するディジタル署名ファイル名は、 s??_data_to_sXX.sig としてください。
s??は送信者(自分)の番号、sXXは送信相手の番号です。)

s19@ubuntu1804:~/Example_RSA_Work$ python rsa_main_mode_bin.py encrypt s19_data_to_s00.MD5 s19_data_to_s00.sig s19_private.key

s19@ubuntu1804:~/Example_RSA_Work$ ls -al
...
...
-rw-r--r-- 1 s19 students    9  4月 23 21:40 s00_public.key       <--- 5-2. 送信相手の公開鍵ファイル
-rw-r--r-- 1 s19 students  140  4月 23 21:52 s19_data.txt         <--- 5-3. 暗号化前元ファイル
-rw-r--r-- 1 s19 students   39  4月 23 21:54 s19_data_to_s00.MD5  <--- 5-5. メッセージダイジェスト
-rw-r--r-- 1 s19 students 1120  4月 23 21:53 s19_data_to_s00.bin  <--- 5-4. s00の公開鍵で暗号化したファイル
-rw-r--r-- 1 s19 students  312  4月 23 21:55 s19_data_to_s00.sig  <--- 5-6. ディジタル署名
-rw-r--r-- 1 s19 students   14  4月 23 21:42 s19_private.key
-rw-r--r-- 1 s19 students    9  4月 23 21:42 s19_public.key

5-7. 暗号化ファイルおよびディジタル署名のメール送信

各自のメールソフトを使って、送信相手宛のインターネットメールを作成します。
送信するメールには、以下の2つのファイルを添付してください。

5-4. で作成した暗号化後のファイル(s??_data_to_sXX.bin)
5-6. で作成したディジタル署名(s??_data_to_sXX.sig)

(s??は送信者(自分)の番号、sXXは送信相手の番号です。)

メールの作成が終わったら、送信してみましょう。

5-8. メールの受信の添付ファイルの配置

電子メールを受け取った方は、
メール内の2つの添付ファイルをExample_RSA_Workの作業ディレクトリに配置してください。

添付ファイルには、

ディジタル署名(sYY_data_to_s??.sig)(5-9.の作業にて、相手の公開鍵で復号)
暗号化データ(sYY_data_to_s??.bin)を(5-10.の作業にて、自分の秘密鍵で復号)

sYYは送信元者の番号、s??は受信者(自分)の番号です。)

の2つのファイルがあるはずです。

送信元者がファイル名を間違って付与していた場合、
自分が作ったファイルに上書きされる恐れがありますので、
ご注意ください。

5-9. ディジタル署名の復号

暗号化ファイルの復号およびディジタル署名の確認

受け取った暗号化ファイルとディジタル署名(メッセージダイジェスト)が一致しているか確認します。

rsa_main_mode_bin.py の引数は以下のようになります。

python rsa_main_mode_bin.py decrypt 受け取ったディジタル署名(sigファイル) 復号後のメッセージダイジェストファイル名 相手の公開鍵ファイル名

ディジタル署名(メッセージダイジェスト)の復号の作業例

s00@ubuntu1804:~/Example_RSA_Work$ python rsa_main_mode_bin.py decrypt s19_data_to_s00.sig s19_data_to_s00.MD5 s19_public.key

復号されたメッセージダイジェストを確認します。

s00@ubuntu1804:~/Example_RSA_Work$ cat s19_data_to_s00.MD5
MD5 : ce6596060ff8e49bd971c0f13191e2c4

受け取った暗号化データ(sYY_data_to_s??.bin)から、メッセージダイジェストを再計算します。

s00@ubuntu1804:~/Example_RSA_Work$ python print_FileHash.py s19_data_to_s00.bin MD5
MD5 : ce6596060ff8e49bd971c0f13191e2c4

一致していますね。

一致していれば、受け取った暗号化データ(sYY_data_to_s??.bin)は、
間違いなくsYYの秘密鍵の所有者本人からの送信データであり、
(sYYの秘密鍵が盗聴されたり、解読されていないという前提であれば)

途中で第三者による改ざんが行われていないことが確認できたことになります。

5-10. 暗号化データの復号

次に、

  • s??_data.bin(暗号化後のファイル)自分の秘密鍵で復号

します。

rsa_main_mode_bin.py の引数は以下のようになります。

python rsa_main_mode_bin.py decrypt 受け取った暗号化データファイル名 復号後のファイル名 自分の秘密鍵

s00@ubuntu1804:~/Example_RSA_Work$ python rsa_main_mode_bin.py decrypt s19_data_to_s00.bin s19_data.txt s00_private.key

復号が終わったら、テキストエディタまたはcatコマンドでファイルの内容を確認します。

s00@ubuntu1804:~/Example_RSA_Work$ cat s19_data.txt
お世話になっております。
s??(○○)です。

メッセージを暗号化して送ります。
読めるかなぁぁ??

正しく、復号できたようです。

(みんなうまくいって、よかった...よかった...めでたしめでたし..となっていることを願う)

6. 公開鍵暗号化方式の代表的な暗号化ツール

RSA暗号化方式を実装したツールとしては、PGP, OpenSSLなどがあります。

これらのツールでも、Example_RSAと同様の考え方で、
鍵ペアの作成や、ディジタル署名やファイルの暗号化/復号の操作ができます。

各自で使い方を調べてみましょう。

そのほか、Python3で鍵の生成、暗号化/復号/電子署名の処理を作成したいのであれば、下記のツールが便利です。

  • pycryptodome

Example_RSAと同等の操作方法をPyCryptodomeで置き換えたプロジェクトも用意しています。

  • PyCryptodomeを利用したファイルの暗号化/復号処理および電子署名の生成/照合処理の作成例

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2