暗号化が必要な時に考えていることをまとめてみる

# はじめに
普段仕事で暗号化が必要な時に、条件によって色々と考えるべきこと、気をつけるべきことがある。
それを、今までまとめたことがなかったので、文章にまとめてみる。
ただ、これはこの時はこうするのがベストだからこうしようということではない。
あくまでも自分が何を考えているかを書いている。
自分自身、このあたりはガンガン考えが更新されたりするので、完全に正しいなんて一切思っていない。
なんなら考え方すら正しいとも思ってない。
自分のことを一切信用してない。
文章も汚い。

あと、具体的な暗号アルゴリズムまでは出さずに、暗号アルゴリズムの特徴で話をしていきたい。
そもそも前提条件に書いたが、各暗号アルゴリズムのセキュリティ強度が十分かは移り変わるものなので。
独自の暗号方式を使うことは意図的に外している。

# 前提条件
まず現在の適切な暗号アルゴリズムが何かを覚えておかないといけない。
セキュリティを考える上で全く意味のないアルゴリズムを使うことを想定して考えてしまうと、色々と無駄になる。

以下でCRYPTRECが「電子政府における調達のために参照すべき暗号のリスト」を公開しているので、これに準じた暗号を選択するようにすれば基本的には間違いない。
CRYPTREC暗号リスト(電子政府推奨暗号リスト)：https://www.cryptrec.go.jp/list.html

ただ、鍵長の話を暗にしているだけで、しっかりとセキュリティとして十分な鍵長を提示してないので、こういったものも参考にする必要がある。
暗号鍵設定ガイダンス：https://www.ipa.go.jp/security/crypto/guideline/ckms_setting.html
~~https://www.ipa.go.jp/security/vuln/ckms_setting.html~~

今は暗号を解読していく時間がどんどん短くなっているし、脆弱性によって突然危険な暗号アルゴリズムになる場合もあるので、常に暗号関連の情報には注目していかないといけない。
もちろん、この中の暗号なら何でもいいということではなくて、状況によって適切なものを選択しないと、いくら強度が高かろうがなんの意味もないということも起きる。

# 何をどう暗号化するのかを考える
まず、どういう環境で何を暗号化するのかを考える。
これが直接的に暗号の強度をどうするか、鍵の管理をどうするべきかを左右する。
そのため、インターネットの回線上にデータが流れることになる、あるいはプログラムの形で渡すことになるなど、どういった環境で暗号化と復号化を行うかを考えないといけない。
普段はその環境に合った要因を考えるので、抜けが出るかもしれない。

ということで、話題になりそうなシチュエーションや内容毎に考えていく
1. 通信の暗号化か
1. ローカルに保存されたデータの暗号化か
1. 組み込みの環境か
1. 通常のPC環境・サーバー環境か
1. 暗号化されたデータを更新するか
1. 暗号化を行う側の環境
1. 復号化を行う側の環境
1. 真贋の確認

## 通信の暗号化か
まずどういったプロトコルで通信するかによる。
TCP/IPの通信でTLSを使えるのであれば使っていった方がいい。
乗っかれるものがあるなら乗っかっていったほうが実装しやすいし、問題も起きにくい。
別のプロトコルで通信を行うとしても、暗号化がサポートされたプロトコルであれば何をどうするか悩むことはない。
そうでなければ、独自に暗号化を行うことを考えなければならない。

独自で考えるとなると難しいことを考えなければアプリケーション層で暗号化をするし、もっとドライバ等で行う必要があれば、別のレイヤーでの暗号化を考える。
とはいえ、今時ほとんど独自で考えることはない気がする。

## ローカルに保存されるデータの暗号化か
基本的にローカルに保存されるということは、そのデータを利用することになるので、一般的なユーザーが利用するような場合、暗号化は解読されると考えた方がいい。
とはいえ、そもそもデータを利用するそのままの形で保存するかという話はあるが、ユーザーが何かしら目にしているものであれば暗号化する意味はない。
そういう意味では暗号化しようとなった場合、ユーザーにデータが改変されないことを目的にしているかを考えないといけない。
実際に、そういう改変されていないことの証明として暗号化するという話が出されることがある。
その場合、データの真贋だけ確認できればいいので、証明書をつけるなりの対応の方が望ましい。
それであれば、公開鍵暗号方式を使うことにより、暗号化に必要な鍵は一緒に保存しなくて良くなるので、データの改変は難しくなる。

利用はするがユーザーの目には触れさせたくないという場合は、共通鍵暗号方式で暗号化するが、セキュリティの強度はあまり高くない。
なので、あくまでも目に触れさせたくないということでしか利用を想定しない。
というか、それ以上を期待するのは、そもそものデータの保存方法を疑った方がいい。

あとは、ユーザーがデータを利用できないようにすることを目的にしている場合がある。
例えば、万が一にもデータが流出した場合に見れないようにする等、データの保護の観点が考えられる。
その場合は、データと鍵を一緒に保存しないように、外から鍵を渡すような措置を考えないといけない。
この場合は基本的にはDBのような場合で、DBを暗号化するかを考えればいい。
ユーザーの環境にインストールするアプリケーション等で出てきたら、データの保存方法を疑った方がいい。
もしくは、実際には目に触れさせたくないというのを過大に考えている場合もあるが、完全なデータの保護はきっぱりと諦めさせるほかない。

## 組み込みの環境か
マイコンのような環境の場合、ローカルにデータを持っていても、一般的にはユーザーがデータにアクセスできないので、あまり暗号化の機会はないと思う。
ただ、マイコンの通信を暗号化するような場合はあり、以下の問題が起きる場合がある。
- 鍵の更新が難しい
- 暗号化/復号化の処理に時間がかかる

つまり、鍵はそのまま持つか、難読化して持つかがあるが、ユーザーが勝手に見れるかや、パフォーマンス等を考えないといけない。
基本的にはファームに書き込んで、保護をかけて読み取りできないようにすると思うので、書き込む場所さえきちんと考えておけば、勝手に見られるようなケースはほとんど無くなる。
署名でなければ共通鍵暗号方式になるし、速度的にも公開鍵暗号よりも遥かに早いので、無理矢理公開鍵暗号を使ってデータを暗号化するメリットはあまりない。
ということで、ファームに鍵を埋め込んだ共通鍵暗号がほぼベストになってくる。

## 通常のPC環境・サーバー環境か
通常のPC環境・サーバー環境と言いながら、あまりシステムの構成は関係ない。
考慮すべきはユーザーからの、暗号化されたデータや鍵へのアクセス性で、それが特にアクセスしやすいPC環境やサーバー環境というだけ。
通常のPCであれば、ユーザーに何かしらのアプリケーションを提供する形になると思うので、データのアクセス性が格段によく、最悪全て解読されると考えた方がいい。
ただデータの取扱が一般的でなく、暗号化されているかどうかも分からないようなものは、解読されるかというとそうとはいえない。
解読できてもそれが何のデータかは、実行ファイルを解析するしかないので、相当に苦労はするだろうが、絶対に解読されないとは"絶対に"言えない。
なので、データの重要度によって保存方法を考える方に重きを置く場合が多い。
重要度といっても、一般的に重要なものというと、セキュリティ絡みか個人情報絡みがほとんどだと思うが。
また、暗号化だけでなく、権限によるアクセス保護も同時に考えないといけない。

アクセス性がいいPC環境でも、社内システムのような外部の人間が入り込めない環境でしか動かないというのであれば、多少の妥協はできないことはない。
しかし、システムにおける一番のセキュリティーホールは人間だということを忘れてはいけない。
悪意を持った人間が内部にいるか、何かしらの人の不備によってデータが持ち出される可能性も考慮しないといけない。
なので、暗号化によるデータの保護についてはきちんと考えないといけない。

サーバーも通常PCとほとんど同じだが、権限の管理や、ネットワークへのアクセスといった要素から、暗号化以前の部分でのセキュリティによって保護されるだろうから、あまり環境的なことで細かく暗号化の話をすることもないと思う。
それよりは、利用する通信の暗号化や、DBであればDBの機能で暗号化することや、サーバーのストレージ自体を暗号化することが出てくる。

## 暗号化を行う側の環境
外部に一切見えない状態で暗号化を行うか、そうでないか。
外部に見える状態は基本的には、配布されたプログラム上で暗号化するような場合である。

暗号化を行う側が外部に見えないのであれば、暗号化に関して考えることはなく、ここはどちらかというと暗号化以外のセキュリティの領域だとは思う。

暗号化を行う側が外部に見えるというのは、例えばユーザーが利用するプログラム内での暗号化等である。
その場合であれば、プログラムのコード内に暗に鍵を埋め込んで配布するか、鍵交換が必要になるので、鍵を解析できないように難読化したデータを持つか、鍵の寿命を短くするかが必要になる。
ただ、基本的に暗号化を行うプログラムが動作する環境で鍵を解析できないというのは信用していないので、埋め込み、難読化、短寿命の全部を入れることを考える。
どんな形でも鍵の情報が外部に出るのであれば、いつか鍵は解析されるものと考えた方がいい。

## 復号化を行う側の環境
ここは環境に対するアクセス性のセキュリティの話で、暗号化のセキュリティの話はそもそも出てこないんじゃないかと思う。
これも、外部に一切見えない状態で復号化を行うか、そうでないか。

復号化を行う側が外部に見えないのであれば、おそらくイントラネット等の外部に公開されない環境だと思う。
その場合には鍵さえ流出しないように気をつけて、共有鍵暗号を使用するのが管理上でも暗号の扱いとしても楽である。
DBの暗号化もこれに則った考えだと思っている。
復号に使用する鍵が解析されると終わりなので、強度だけを考えて、わざわざパフォーマンスの悪い鍵を選択する理由はないと思う。

## 真贋の確認
ただデータの真贋を確認したいという場合、それは本来暗号化を持ち出すことではない。
データの誤りについては言わずもがな。
データの誤りを検出して、復号化の成否を確認するようになっているのであればそうだが、それだけであればパフォーマンスが悪い。
データの偽装に対する対策として、復号化できたから偽装されてない正しいデータだね、とか言う人がいるが、復号化できる=正しいデータではない。
そもそもそれは暗号化側のチェックの仕組みを使ってるだけだし。
わざわざ言うことでもないと思うけれど、たまに言う人がいるので…

データの真贋の確認にはハッシュ関数でハッシュ値を付与する等があるが、あくまでも真贋の確認としてだけ考えてほしい。
ただ、これも脆弱性がある場合があったり、衝突による問題があるので、多少は気をつけないといけないけれど。

あとは暗号化ではないけど、証明書を付けておけとしか言えない。

# 最後に
多分そのうち自分で見ても変なこと言ってるなってなるくらいに技術と知識の更新が激しいところなので、あんまり鵜呑みにせず色々調べて、その時点での最新の知識を身につけて考えてほしい。
人生で一番まとまりのないこと書いたという自負があるくらい、要素が多すぎて本当にまとまらないので、本当状況ごとに色々考えるしか無い。