暗号技術への入門と実装(perl)

# ゴール
* 暗号技術の基本的な考え方が理解出来る
* 簡易なアルゴリズムを参考に暗号化、復号化のプログラムを考えることができる

# 背景
仕事では特別な関わりがないが、元々セキュリティの世界に興味があった。
そんな中、仕事でも若干セキュリティに関連するような仕事をかじる機会があって、
この機会に本格的に勉強をしてみようという気持ちになった。
たまたま、『暗号技術入門』(結城 浩 SB Creative 2015)という本に出会って、それがとてもわかりやすく、
よい本だったので、それに習い暗号化技術の基礎概念と、簡単な暗号化アルゴリズムの実装をしてみようと思った。

# 暗号技術の基本
暗号技術は、基本として以下のような概念に基づいたものとなっている。

* 平文
    * 暗号化の対象となる情報
* 暗号化
    * 平文を元の情報が人間やコンピュータにわからないように変換する
* 暗号文
    * 暗号化された情報
* 復号化
    * 暗号化された情報を平文へ還元する
* 鍵
    * 暗号化と復号化の際に用いる情報

![encrypt_pic1.png](https://qiita-image-store.s3.amazonaws.com/0/143910/7823fd81-c49b-48a0-acca-127fbc115238.png)

![encyrpt_pic2.png](https://qiita-image-store.s3.amazonaws.com/0/143910/615c4ee9-6616-79d1-8133-00214535388d.png)
なお、この暗号化と復号化に同じ鍵を使うことを対称暗号という。
情報の送信者と受信者は、共通した非公開の鍵(秘密鍵)を用いて暗号化と復号化を行う。(図.1,2)
したがって、対称暗号はその鍵の秘匿性とパターン数がセキュリティの強度に大きく影響する。

次に紹介するシーザー暗号は、この対称暗号の一つである。

# シーザー暗号
* ローマの将軍ジュリアス・シーザー(ユリウス・カエサル)が使っていたとされる暗号
* アルファベットを、任意の数に従い、"ずらす"というアルゴリズム
* "ずらす数"が鍵となる
* アルファベットの数=鍵のパターン数=26
* 例えば"hoge"という文字列を3という鍵で暗号化すると"KRIH"という暗号文となる(図.3)

![encrypt_pic3.png](https://qiita-image-store.s3.amazonaws.com/0/143910/220f2e6a-a9d7-503d-cd9b-2217f6fd36f7.png)

# シーザー暗号の実装
より暗号化アルゴリズムのイメージを具体的につかむために、実装してみた。
単純なアルゴリズムなので、とても簡単だ。

```perl:c_encrypt.pl
use strict;
use warnings;
use utf8;
use Getopt::Kingpin;
use Path::Tiny;

my $kingpin = Getopt::Kingpin->new;

my $filename = $kingpin->arg('file', 'filename')->required->string;
my $key      = $kingpin->arg('key', 'key of encryption')->required->string;
my $decrypt  = $kingpin->flag('decrypt', 'decrypt')->short('d')->bool;
$kingpin->flags->get("help")->short('h');

$kingpin->parse;

die "Error:out of key range\n" if $key < 0x00 or $key > 0x7F;

my $file = path $filename;
my $data = $file->slurp;

my @proccessed_data;

unless ($decrypt) {
    foreach my $ch (split //, $data) {
        my $roatated = (ord $ch) + $key;
        $roatated = $roatated - 0x7F if $roatated > 0x7F;
        push @proccessed_data, chr $roatated;
    }
} else {
    foreach my $ch (split //, $data) {
        my $roatated = (ord $ch) - $key;
        $roatated = $roatated + 0x7F if $roatated < 0x00;
        push @proccessed_data, chr $roatated;
    }
}

print @proccessed_data;
```
* アルファベットではなくASCIIコードローテーションで実装
* 引数に平文のファイル名と鍵(0~127)を指定する
* オプションなしで暗号化、`--decrypt`オプションで復号化する
* 処理したものを標準出力へ出力する

```
$cat log.txt
date Thu Apr 11 04:41:25 pm 2013
base hex  timestamps absolute
internal events logged
// version 8.0.0
Begin Triggerblock Thu Apr 11 04:41:25 pm 2013
   0.000000 Start of measurement
   0.001316 CAN 1 Status:chip status error active
   0.001399 1  1F3             Rx   d 3 00 10 00  Length = 146000 BitCount = 77 ID = 499
   0.002763 1  1E5             Rx   d 8 4C 00 21 10 00 00 00 B9  Length = 228000 BitCount = 118 ID = 485
   0.003009 1  710             Rx   d 8 00 5F 00 00 00 00 13 BE  Length = 238000 BitCount = 123 ID = 1808
   0.003175 1  C7              Rx   d 4 00 38 26 9B  Length = 158000 BitCount = 83 ID = 199
   0.003349 1  1CC             Rx   d 4 00 00 00 00  Length = 165883 BitCount = 87 ID = 460
   0.003586 1  F9              Rx   d 8 00 DA 40 33 D0 63 FF 1C  Length = 228000 BitCount = 118 ID = 249
   0.003738 1  1CF             Rx   d 3 00 00 05  Length = 144000 BitCount = 76 ID = 463
   0.003976 1  711             Rx   d 8 00 23 00 7E FF EB FC 6F  Length = 230000 BitCount = 119 ID = 1809
   0.004148 1  1D0             Rx   d 4 00 00 00 00  Length = 164000 BitCount = 86 ID = 464
   0.004382 1  C1              Rx   d 8 30 14 F6 08 32 B4 F7 70  Length = 226000 BitCount = 117 ID = 193
   0.004615 1  C5              Rx   d 8 31 27 F8 44 32 B0 F8 5C  Length = 224121 BitCount = 116 ID = 197
   0.004825 1  BE              Rx   d 6 00 00 4D 00 00 00  Length = 202242 BitCount = 105 ID = 190
   0.005051 1  D1              Rx   d 7 80 00 BF FE 00 FE 00  Length = 218121 BitCount = 113 ID = 209
   0.005292 1  C9              Rx   d 8 80 2C 5A 60 00 00 18 00  Length = 232242 BitCount = 120 ID = 201
   0.005538 1  1C8             Rx   d 8 80 00 00 00 FF FE 3F FE  Length = 238121 BitCount = 123 ID = 456
   0.005774 1  18E             Rx   d 8 00 00 00 84 78 46 08 45  Length = 228242 BitCount = 118 ID = 398

$perl c_encrypt.pl log.txt 7 > encrypted_log.txt

$cat encrypted_log.txt
kh{l'[o|'Hwy'88'7;A;8A9<'wt'978:ihzl'ol''{ptlz{htwz'hizvs|{lpu{lyuhs'l}lu{z'svnnlk66'}lyzpvu'?5757Ilnpu'[ypnnlyisvjr'[o|'Hwy'88'7;A;8A9<'wt'978:'''75777777'Z{hy{'vm'tlhz|yltlu{'''75778:8='JHU'8'Z{h{|zAjopw'z{h{|z'lyyvy'hj{p}l'''75778:@@'8''8M:'''''''''''''Y'''k':'77'87'77''Slun{o'D'8;=777'Ip{Jv|u{'D'>>'PK'D';@@'''75779>=:'8''8L<'''''''''''''Y'''k'?';J'77'98'87'77'77'77'I@''Slun{o'D'99?777'Ip{Jv|u{'D'88?'PK'D';?<'''7577:77@'8''>87'''''''''''''Y'''k'?'77'<M'77'77'77'77'8:'IL''Slun{o'D'9:?777'Ip{Jv|u{'D'89:'PK'D'8?7?'''7577:8><'8''J>''''''''''''''Y'''k';'77':?'9='@I''Slun{o'D'8<?777'Ip{Jv|u{'D'?:'PK'D'8@@'''7577::;@'8''8JJ'''''''''''''Y'''k';'77'77'77'77''Slun{o'D'8=<??:'Ip{Jv|u{'D'?>'PK'D';=7'''7577:<?='8''M@''''''''''''''Y'''k'?'77'KH';7'::'K7'=:'MM'8J''Slun{o'D'99?777'Ip{Jv|u{'D'88?'PK'D'9;@'''7577:>:?'8''8JM'''''''''''''Y'''k':'77'77'7<''Slun{o'D'8;;777'Ip{Jv|u{'D'>='PK'D';=:'''7577:@>='8''>88'''''''''''''Y'''k'?'77'9:'77'>L'MM'LI'MJ'=M''Slun{o'D'9:7777'Ip{Jv|u{'D'88@'PK'D'8?7@'''7577;8;?'8''8K7'''''''''''''Y'''k';'77'77'77'77''Slun{o'D'8=;777'Ip{Jv|u{'D'?='PK'D';=;'''7577;:?9'8''J8''''''''''''''Y'''k'?':7'8;'M='7?':9'I;'M>'>7''Slun{o'D'99=777'Ip{Jv|u{'D'88>'PK'D'8@:'''7577;=8<'8''J<''''''''''''''Y'''k'?':8'9>'M?';;':9'I7'M?'<J''Slun{o'D'99;898'Ip{Jv|u{'D'88='PK'D'8@>'''7577;?9<'8''IL''''''''''''''Y'''k'='77'77';K'77'77'77''Slun{o'D'9799;9'Ip{Jv|u{'D'87<'PK'D'8@7'''7577<7<8'8''K8''''''''''''''Y'''k'>'?7'77'IM'ML'77'ML'77''Slun{o'D'98?898'Ip{Jv|u{'D'88:'PK'D'97@'''7577<9@9'8''J@''''''''''''''Y'''k'?'?7'9J'<H'=7'77'77'8?'77''Slun{o'D'9:99;9'Ip{Jv|u{'D'897'PK'D'978'''7577<<:?'8''8J?'''''''''''''Y'''k'?'?7'77'77'77'MM'ML':M'ML''Slun{o'D'9:?898'Ip{Jv|u{'D'89:'PK'D';<='''7577<>>;'8''8?L'''''''''''''Y'''k'?'77'77'77'?;'>?';='7?';<''Slun{o'D'99?9;9'Ip{Jv|u{'D'88?'PK'D':@?%

$perl c_encrypt.pl -d encrypted_log.txt 7 > decrypted_log.txt

$cat decrypted_log.txt
date Thu Apr 11 04:41:25 pm 2013
base hex  timestamps absolute
internal events logged
// version 8.0.0
Begin Triggerblock Thu Apr 11 04:41:25 pm 2013
   0.000000 Start of measurement
   0.001316 CAN 1 Status:chip status error active
   0.001399 1  1F3             Rx   d 3 00 10 00  Length = 146000 BitCount = 77 ID = 499
   0.002763 1  1E5             Rx   d 8 4C 00 21 10 00 00 00 B9  Length = 228000 BitCount = 118 ID = 485
   0.003009 1  710             Rx   d 8 00 5F 00 00 00 00 13 BE  Length = 238000 BitCount = 123 ID = 1808
   0.003175 1  C7              Rx   d 4 00 38 26 9B  Length = 158000 BitCount = 83 ID = 199
   0.003349 1  1CC             Rx   d 4 00 00 00 00  Length = 165883 BitCount = 87 ID = 460
   0.003586 1  F9              Rx   d 8 00 DA 40 33 D0 63 FF 1C  Length = 228000 BitCount = 118 ID = 249
   0.003738 1  1CF             Rx   d 3 00 00 05  Length = 144000 BitCount = 76 ID = 463
   0.003976 1  711             Rx   d 8 00 23 00 7E FF EB FC 6F  Length = 230000 BitCount = 119 ID = 1809
   0.004148 1  1D0             Rx   d 4 00 00 00 00  Length = 164000 BitCount = 86 ID = 464
   0.004382 1  C1              Rx   d 8 30 14 F6 08 32 B4 F7 70  Length = 226000 BitCount = 117 ID = 193
   0.004615 1  C5              Rx   d 8 31 27 F8 44 32 B0 F8 5C  Length = 224121 BitCount = 116 ID = 197
   0.004825 1  BE              Rx   d 6 00 00 4D 00 00 00  Length = 202242 BitCount = 105 ID = 190
   0.005051 1  D1              Rx   d 7 80 00 BF FE 00 FE 00  Length = 218121 BitCount = 113 ID = 209
   0.005292 1  C9              Rx   d 8 80 2C 5A 60 00 00 18 00  Length = 232242 BitCount = 120 ID = 201
   0.005538 1  1C8             Rx   d 8 80 00 00 00 FF FE 3F FE  Length = 238121 BitCount = 123 ID = 456
   0.005774 1  18E             Rx   d 8 00 00 00 84 78 46 08 45  Length = 228242 BitCount = 118 ID = 398
```
とりあえず暗号化と復号化をすることができた。

# ブルートフォースアタックによる攻撃の危険性
では、今回紹介した暗号アルゴリズムの強度とはどの程度なのであろうか。
残念ながら、シーザー暗号は極めて脆弱な暗号化アルゴリズムなので、ブルートフォースアタック等の、
簡単な手段によって解読されてしまう。

* ブルートフォースアタック
    * わかりやすい日本語で言う「総当たり」でのセキュリティ攻撃手法
    * 上記のシーザー暗号の実装では鍵のパターンは0~127の128パターンのみ
    * したがってセキュリティ強度は2桁の数字列パスワード程度しかない
* 上記の暗号文であれば、並の攻撃者でもおそらく数分で解読できてしまう
    * 具体的に上記の暗号分であれば、頻出する" ' "の文字列より、ASCIIコード数への加算を推測される危険性が高い

# まとめ
* 今回特に知識のない状態から学習してみたが、体系的に学びやすい分野だと感じた
    * 体系的な学びやすさの一つとして、セキュリティ分野ではあらゆるアルゴリズムは、専門家により標準化され公開されたものを使用するべきである、という考え方があるため、と思われた
        * それはこの分野の常識である、隠すことによるセキュリティ(security of obscurity)をしないという思想が基礎となっている
* 今回紹介した対称暗号の標準はAES(Advanced Encryption Standard)というアルゴリズムとなっている
    * 次はこのAESの実装を試みてみたい