プログラマの暗号化入門


暗号化について理解が不十分なまま何となく動くプログラムを書いている人が意外に多いような気がします。
最低限これだけ覚えておけば、という内容だけを記載しました。
通常業務で困らないレベルの知識を身につけましょう!

これだけは言っておきたかったこと

暗号化の対語は復号です。
復号化ではありません。よく間違われているので注意!(「暗号化」の対語が「復号化」ではない理由
これを知っていると少しドヤ出来ますよ。

用語集(登場人物)

  • 平文(ひらぶん)
    暗号化されていない元のデータのこと。(英語ではplain text)
    https://ja.wikipedia.org/wiki/%E5%B9%B3%E6%96%87

  • 暗号文
    何らかの暗号アルゴリズムで秘匿化されたデータのこと。(英語ではcipher text)
    https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E6%96%87


  • 平文を暗号文にする際に使用するデータのこと。(英語ではkey)
    鍵のデータを知っている人のみが暗号文を平文に戻すことが出来ます。
    基本的に鍵のデータは他人に知られてはいけないものです。
    https://ja.wikipedia.org/wiki/%E9%8D%B5_(%E6%9A%97%E5%8F%B7)

  • 初期ベクトル
    同じ平文が同じ暗号文にならないようにするために使用するデータのこと。(英語ではinitial vector、もしくはIV)
    平文中に同じデータが繰り返し出てきた場合に、すべてが同じ暗号文に変換されてしまうと、その頻度などから平文が推測されやすくなってしまいます。
    それでは強度的に不安なので、初期ベクトルを使って同じ暗号文にならないようにします。
    初期ベクトルは鍵と違って他人に知られても問題ないものです。
    https://ja.wikipedia.org/wiki/%E5%88%9D%E6%9C%9F%E5%8C%96%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB

  • 暗号モード
    初期ベクトルをどのように使用するか決めるモードのこと。(英語では、cipher mode)
    初期ベクトルの利用方法はいくつかの種類があります。(ECB、CBCモードなど)
    https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E5%88%A9%E7%94%A8%E3%83%A2%E3%83%BC%E3%83%89

  • パディング
    暗号アルゴリズムにもよりますが、暗号化をするにあたって、平文のデータ長は何らかの倍数長でなければなりません。(例えば16byteの倍数長)
    平文が倍数長になっていない場合に、平文に無駄なデータ(詰め物)を付加することをパディングすると言います。
    パディングデータは復号時には除去されます。

暗号化は二種類ある

逆に言うと2つしかありません。まずはこの2つをしっかりと認識できるようにしましょう。

  • 共通鍵暗号
    暗号鍵と復号鍵が同じ鍵なので共通鍵暗号と言われます。
    家の玄関の鍵と同じ仕組みです。
    後述する公開鍵暗号に比べて、暗号化の処理速度が速いという特徴があります。

  • 公開鍵暗号
    暗号鍵と復号鍵が違う鍵であり、基本的には暗号化に使う鍵を公開鍵、復号に使う鍵を秘密鍵と言います。
    公開鍵を人に渡して暗号文を送ってもらい、自分で隠し持っている秘密鍵で復号するというのが基本的な使い方です。
    公開鍵は誰に対して公開しても良いものなので、インターネットなどで使いやすいという特徴があります。

まずは共通鍵暗号について覚えよう

業務でよく使うのは共通鍵暗号の方です。まずはこちらの使い方から覚えましょう。
メジャーな暗号アルゴリズムは、DES、AESなどです。
共通鍵暗号は別名ブロック暗号とも呼ばれます。暗号化する際にブロック単位で処理を行うためです。(8byteや16byte単位など)

共通鍵暗号で暗号化する

暗号化とは何をすることでしょうか?
すごく単純に説明すると、「あるバイナリデータをぐちゃぐちゃにして、別のバイナリデータを作成すること」です。
(バイナリデータが分からない方はバイト配列のことだと思ってもらえば良いかと思います。 )
鍵、初期ベクトルの値によって出力されるぐちゃぐちゃデータが変わるので、それらの値を知っている人しか元に戻せないという訳です。

よく誤解されるので気を付けて欲しいのは、ある文字列を暗号化して別の文字列にするというような処理は出来ないということです。
文字列であっても必ず一度バイナリデータに変換した上で、暗号化が行われます。(日本語の文字列であればエンコーディングというややこしいものが関わってきます。Shift-JISとかUTF-8などの話です。)

ここでプログラマ向けに暗号化を単純化したものを示したいと思います。

/* 暗号化する関数 */
byte[] encrypt(byte[] plainText, byte[] key, byte[] iv, enum cipherMode)
{
    // keyとivとcipherModeを使ってplainTextをぐちゃぐちゃにかき混ぜる処理をする
    // ...

    // 暗号文が出来上がる
    return cipherText;
}

登場人物を理解することが大切です。
入力として、平文、鍵、初期ベクトル、暗号モードを渡すと、
出力として、暗号文が出来上がる。

これだけを理解していれば、まずは十分なのです。
自分で暗号アルゴリズムを実装することはまずありません。
どのようにぐちゃぐちゃにかき混ぜているかは知っている必要はない訳です。

では、今度は復号の方を見てみましょう。

/* 復号する関数 */
byte[] decrypt(byte[] cipherText, byte[] key, byte[] iv, enum cipherMode)
{
    // keyとivとcipherModeを使ってcipherTextを元に戻す処理をする
    // ...

    // 平文が出来上がる
    return plainText;
}

入力として、暗号文、鍵、初期ベクトル、暗号モードを渡すと、
出力として、平文が出来上がる。
平文と暗号文が逆になっただけですね。

おまけ

厳密にいうと、鍵と初期ベクトルの長さは暗号アルゴリズムによって制限があります。
例えば暗号アルゴリズムがAESの場合、鍵長は(16 or 24 or 32 byte)、初期ベクトル長は(16 byte)である必要があります。
またどの暗号アルゴリズムでも、平文は必ずパディングされている必要があります。(パディングのやり方にも色々種類があったりします)

さいごに

共通鍵暗号(ブロック暗号)を利用するに当たっての必要な知識について、ポイントを絞ってざっと記述してみましたが、参考になったでしょうか?
少しでも理解の助けになっていれば幸いです。暗号最高!

参考元

「暗号化」の対語が「復号化」ではない理由
平文(Wikipedia)
暗号文(Wikipedia)
鍵 (暗号)(Wikipedia)
初期化ベクトル(Wikipedia)
暗号利用モード(Wikipedia)