暗号

プログラマの暗号化入門【2022年 改訂版】

この記事で分かること

  • 暗号処理を書く際に最低限知っておくべきこと
  • 暗号処理の登場人物(用語集)
  • 2022年現在オススメの暗号モードについて

この記事では、プログラマが暗号処理を書く際に最低限知っておくべき知識について、分かりやすく解説しています。

暗号化の処理について人と話すと、理解がイマイチだったり、全く分からないままコードを書いている方が意外に多いと感じます。

そのような方に向けて、暗号化についての卒論を書いたことがある私が、通常の業務で困らない程度の知識が得られるように説明します。

暗号に関する用語集や、最新の情報を加えたオススメの暗号モードについても記載していますので、ぜひ最後までご覧ください!

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

暗号化の対語は復号です。

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

ゴイチ

復号化と呼んでも業務上特に困ることは無いのですが、心の中で「こいつ暗号素人だな?」とは思っています。

性格が悪いな!

ツッコミを入れる人

暗号化は2種類ある

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

  • 共通鍵暗号

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

    暗号化と復号を別々の鍵で行い、他人に公開してもよい公開鍵と、公開してはいけない秘密鍵の二種類の鍵がある方式を公開鍵暗号と言います。
    公開鍵を暗号化に使い、秘密鍵を復号に使うのが基本的な使い方ですが、公開鍵と秘密鍵の役割を逆にすることもできます。
    秘密鍵で暗号化することを署名、公開鍵で復号することを署名検証と言います。

    公開鍵は誰に対して公開しても良いものなので、公開鍵証明書の形で配布することができます。
    共通鍵暗号のように同じ鍵を共有する必要がないので、鍵配送の問題が発生せず、インターネットなどで使いやすいという特徴があります。

    共通鍵暗号に対して処理速度が遅いので、共通鍵暗号の鍵を配送するためだけに使われることが多いです。

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

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

登場人物(用語集)

平文(ひらぶん)

暗号化されていない元のデータのこと。(英語では 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)
初期ベクトルの利用方法はいくつか種類があります。(CBC、CTRモードなど)
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

パディング

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

共通鍵での暗号化とは?

暗号化とは何をすることでしょうか?

単純に説明すると、「あるバイナリデータをぐちゃぐちゃにかき混ぜて、別のバイナリデータを作成すること」です。
(バイナリデータが分からない方はバイト配列のことだと思って下さい。 )
鍵、初期ベクトルの値によって出力されるぐちゃぐちゃデータが変わり、元に戻せるのは同じ鍵と初期ベクトルを知っている人だけです。

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

ゴイチ

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

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

    // 暗号文を返す
    return cipherText;
}

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

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

ゴイチ

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

/* 復号する関数 */
byte[] decrypt(byte[] cipherText, byte[] key, byte[] iv, enum cipherMode)
{
    // key & iv & cipherMode を使って cipherText を元に戻し plainText に出力

    // 平文を返す
    return plainText;
}

入力として、暗号文、鍵、初期ベクトル、暗号モードを渡すと、
出力として、平文が出来上がる。

ゴイチ

平文と暗号文が逆になっただけですね!

共通鍵暗号の制限について

厳密に言うと、鍵と初期ベクトルの長さは自由に選べる訳ではなく、暗号アルゴリズムによって制限があります。
例えば、暗号アルゴリズムがAESの場合、鍵長は(16 or 24 or 32 byte)、初期ベクトル長は(16 byte)である必要があります。

オススメの暗号モード

ゴイチ

独断と偏見によるオススメの暗号モード一覧表です

暗号モードオススメ度
ECB
CBC
CFB
OFB
CTR
GCM
おすすめ共通鍵暗号モード

GCMモードとは?

2022年現在最も安全性が高く、広く使われている共通鍵暗号モードです。
暗号化の機能と同時に認証の機能も持っており、暗号文が改ざんされていないことを検証可能なモードです。

GCMモードに関しては、別記事で詳しく解説していますので、興味があれば以下の記事をご覧下さい。

AES-GCM 仕組みの解説とJavaサンプルコード

この記事では、共通鍵暗号のデファクトスタンダードとなっている、AES-GCMモードについての解説をしています。 AES-GCMとは、近年様々な用途で用いられているAESの暗号モードの一つです。主な利用 ...

続きを見る

まとめ

最後に、この記事の内容をまとめます。

要点まとめ

  • 暗号方式には、同じ鍵を使う共通鍵暗号と、違う鍵を使う公開鍵暗号がある
  • 暗号処理の登場人物は、平文、暗号文、鍵、初期ベクトル、暗号モード、パディングである
  • 暗号化の処理とは、鍵と初期ベクトルを使って元のデータが分からないようにかき混ぜること
  • 暗号文を復号できるのは同じ鍵、初期ベクトルを知っている人のみ
  • 暗号モードによって強度が変わる。おすすめはGCMモード

共通鍵暗号や公開鍵暗号を利用するに当たっての必要な知識について、ポイントを絞って解説しました。
少しでも理解の助けになれば幸いです。

ゴイチ

暗号最高!

(注)この記事はQiitaに投稿した過去の記事を再構成したものです

この記事は役に立ちましたか?

  • この記事を書いた人
アバター画像

ゴイチ

ソフトウェアエンジニア歴20年。 C/C++, C#, Java, Kotlinが得意で、組込系・スマホ・大規模なWebサービスなど幅広いプログラミング経験があります。 現在は某SNSの会社でWebエンジニアをしています。

-暗号
-, ,