暗号方式とSSL/TLS

本記事では、暗号化通信を使う目的と暗号化技術について簡単に説明し、SSL/TLSに関してそれがどのように使われているかを説明します。
また、組み込み開発においてはどのように関わっているかも示します。

# 暗号化通信を使う目的

悪意ある第三者、通信相手に下記の四つが行われないようにするため、暗号化の仕組みが使われています。

- 盗聴
  - 通信内容が第三者に筒抜けとなってしまうこと
    - ex. 重要なメールの内容が関係のない第三者に盗み見られていた
- 改竄
  - 送ったデータの内容が書き換えられてしまっていること
    - ex. 送信したメールの内容が、受信した相手が確認した時には書き換えられてしまっていた
- なりすまし
  - 通信相手自体が、想定した相手ではなく、悪意ある第三者であること
    - ex. 取引先へのメールアドレスでメールを送ったのに、違う相手にメールが送られてしまっていた
- 否認
  - 通信相手が送ったデータを送っていないと言い張られてしまうこと
    - ex. ショッピングサイトで購入し、オンラインで支払いをしたはずが、サイト運営者から支払いがされていないと言い張られた

# 暗号化技術

先ほど示した四点に対抗するための技術について示します。

- 共通鍵暗号(対称暗号)
  - 暗号と復号を同じ鍵で行う
  - 盗聴の対策として使用(機密性)
    - ex. AES, 使い捨てパッド

- 公開鍵暗号
  - 暗号と復号で別の鍵(公開鍵と秘密鍵)を使う。データの送信者が公開鍵で暗号化し、受信者が秘密鍵で復号する。公開鍵は誰でも使用でき、秘密鍵はデータの受信者しか持たない
  - 盗聴の対策として使用(機密性)
    - ex. RSA, DSA, ECDSA

- 一方向ハッシュ関数
  - ハッシュ関数によりデータのハッシュ値を算出する。送受信等の処理後も同じハッシュ値となることを確認する
  - 改竄の対策として使用(正真性)
    - ex. SHA-1, SHA-2, SHA-3

- メッセージ認証コード(MAC)
  - 鍵に依存する一方向ハッシュ関数。送信者と受信者だけが共有している鍵で、任意の長さのデータから固定ビット長のハッシュ値を計算する。送受信等の処理後も同じハッシュ値となることを確認する
  - なりすましの対策として使用(認証)
    - ex. HMAC,AES-CMAC

- デジタル署名
  - 公開鍵暗号を使用して、メッセージのハッシュ値を送信者が秘密鍵で暗号化、受信者が公開鍵を使用して復号化することで否認を防ぐ。(公開鍵で復号できない場合は否認の可能性があると言える)
  - 否認の対策として使用(否認不可能性)
    - ex. RSA、DSA、ECDSA

暗号化技術は、アルゴリズムが公開されていて解読が難しいものほど強固であると認識されます。詳しくは参考文献の書籍に書いてあります。良い本なので興味がある方はぜひ買ってください。

# SSL/TLS

世界で最も使用されている暗号通信のプロトコルです。
より安全に通信を行うには盗聴、改竄、なりすまし、否認の全てを防ぐ必要があるので、これらを防ぐために使用されます。SSL/TLSは共通鍵暗号(対称暗号)、公開鍵暗号、一方向ハッシュ関数、メッセージ認証コード、デジタル署名を駆使して暗号化通信を行います。
HTTPなどでやり取りしているデータを暗号化するのによく使用されています。


SSL/TLSがソフトウェアの構成上どこに配置されているかを示すと、下記のようになります。TCPとアプリケーション(HTTPなど)の間で、データの暗号化と復号化を行います。

![SSL_TLS構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/c3a7f16b-72e7-7d9b-de63-e38bf6decd86.png)


また、SSL/TLSのライブラリ内で暗号化の鍵などを生成する都合上、組み込み開発では乱数生成用ハードウェアのデバイスドライバを使う事も多いです。乱数に関しては後述します。

## SSL/TLSの仕組み

SSL/TLSのプロトコルは、下記の画像のような構造になっています。

![TLSプロトコル構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/d4a21d0c-af2d-05c6-da4b-03a6005e8781.png)



下層となるTLSレコードプロトコルがデータの暗号化・復号化と、送受信する暗号化データの分割・結合を行います。使用するカギとアルゴリズムはハンドシェイクプロトコルで設定します。
上層となるTLSハンドシェイクプロトコルで主に行うことは下記にまとめます。

1. ハンドシェイクプロトコル
    - 使用する暗号スイート(サイファースイート)設定・鍵交換を行います。証明書による認証に関してもここで行います
2. 暗号仕様変更プロトコル
    - 暗号通信を行うプロトコルを切り替えます。ハンドシェイクプロトコルで設定した暗号スイートに設定を行います
3. 警告プロトコル
    - 暗号化通信をする上で何らかのエラーが発生した際に、通信先にエラーを通知します
4. アプリケーションプロトコル
    - アプリケーション用のデータの送受信の時に使用されます。暗号化と復号化はTLSレコードプロトコルで行うので、その際に使用するトンネルのようなものと考えれば問題ないかと思います

上記において、暗号スイート(サイファースイート)とハンドシェイクプロトコル
に関して説明していきます。

### 暗号スイート(サイファースイート)

SSL/TLSでは、脆弱性が見つかった際に別の暗号技術で通信できるようにするため、どの暗号技術を使用するかは入れ替え可能になっています。
ただし、あまり自由でも運用性が悪いため、良く使用される組み合わせに関してはあらかじめ設定が用意されています。これを暗号スイート(サイファースイート)と呼んでいます。
暗号スイートには下記のようなものがあります。ここではTLS1.2でよく使用されるものを挙げます。

```
1: ECDHE-RSA-AES256-GCM-SHA384
2: ECDHE-ECDSA-AES128-GCM-SHA256
```

暗号スイートは使用する暗号方式を「-」で区切っています。各値を下記に説明します。

- ECDHEは鍵交換アルゴリズムを指定しています
- RSA, ECDSAは、公開鍵の認証方式を指定しています
- AES128、AES256 は通信の暗号化に使う暗号方式を指定しています
- GCMは暗号利用モードを指定しています
- SHA256、SHA384 はメッセージ認証コードの暗号方式を指定しています

図で示すと下記のようになります。

![暗号スイート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/de043c4b-2555-46ff-0867-8971c46899e0.png)


また、暗号スイートには推奨されるものがいくつかあり、[こちら](https://wiki.mozilla.org/Security/Server_Side_TLS )のMozillaのWikiページには、現状(2024/7)で推奨される暗号スイートが示されています。対応する暗号スイートを決める際は、できるだけ信用できるサイトや仕様であるRFCの文書を参照して考えるべきかと思います。

### ハンドシェイクプロトコル

SSL/TLSにおけるハンドシェイクは、主に共有鍵の生成と証明書の交換を行います。また、暗号化通信で使用する暗号方式を決めます。
ハンドシェイクで行うのは下記となります。詳しいプロトコルの理解が必要なければ下記の認識で問題ないと思います。

1. クライアントはサーバーに使用できる暗号方式を通知
2. サーバーは使用する暗号方式と証明書をクライアントに通知
3. クライアントはサーバーに共有鍵生成に必要な情報を通知。(必要があれば証明書も通知)
4. 暗号化通信の開始をお互いに通知

## 組み込み開発でのSSL/TLSを使用する際のソフトウェア構成

ここからは、組み込み開発においてSSL/TLSを使用する場合の構成について説明します。
なぜ組み込み開発にフォーカスしたかというと、組み込み開発で使用されるマイコンが搭載されている評価ボードには暗号プロセッサや乱数発生器が搭載されている事があるからです。
よって、SSL/TLSのライブラリからデバイスドライバを呼び出すことになるため、ソフトウェアの構成が変わります。
下記に組み込み開発におけるソフトウェアの構成を示します。SSL/TLSのライブラリから暗号プロセッサや、乱数生成器のデバイスドライバを使用することになります。

![組み込みのソフトウェア構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/86e40f7c-2d74-ea6b-6701-b655def607a2.png)


ただし、上記の構成はあくまで暗号プロセッサや乱数発生器のデバイスドライバが用意されている場合のものになります。
よって、使用するライブラリや暗号方式、用意されているデバイスドライバによっては、暗号化・復号化や乱数生成のハードウェアやデバイスドライバが無い場合もあります。この場合はSSL/TLSのライブラリ内で暗号化・復号化・乱数生成が行われます。
大抵の場合、ハードウェアによる暗号化・復号化・乱数生成のほうがソフトウェアよりも高速になります。よってパフォーマンスを考えれば、暗号化・復号化や乱数生成は用意されているハードウェアを使用するのが一番ですが、デバイスドライバがない場合は開発コストもかかるので、このあたりの選択はバランスを取る必要があります。

## SSL/TLS ライブラリ

SSL/TLSによる暗号化通信に使用されているライブラリに関して説明します。よく使用されているのは下記の三つです。

- OpenSSL
  - PC用アプリケーションやサーバーなどで使用されることが多いオープンソース。Windows, Linux, Mac OSに対応
- wolfSSL
  - 組み込み開発用ライブラリ。商用で使う場合はライセンス料を払う必要があります
- mbedTLS
  - 組み込み開発用ライブラリ。商用であるかどうかに関わらずライセンス料は不要です

昨今ではハードの発達も伴って、組み込み開発かどうかにかかわらずLinuxの環境ではOpenSSLが使われていることが多いです。ただ、FreeRTOSなどの組み込み開発用のOSを使用しなければいけない場合はwolfSSlやmbedTLSが使用されることも多いです。

# 乱数生成と乱数発生器

## 乱数生成と暗号化

乱数生成は、暗号技術において鍵生成や暗号化の計算における初期値(初期ベクトル)に使用されているため、ここで説明いたします。もちろんSSL/TLSにも使用されています。
乱数の性質は下記の三つがあり、無作為性＜予測不可能性＜再現不可能性の順に、乱数として制限が厳しいものとなります。また、暗号技術として使用するには、最低でも予測不可能性を持つものでないといけません。

- 無作為性
  - 統計的に偏りがなく、並べても規則性のないでたらめな数列
- 予測不可能性
  - 過去の数列から予測が不可能
- 再現不可能性
  - 生成した乱数を並べた際に同じ数列を再現できないもの(再現するには数列そのものを保存しておく以外方法がない)

## 乱数生成と組み込み開発

コンピュータによる乱数生成は、ハードウェアのセンサー(温度、気圧センサやマウスの運動量など)を使って行うことで、予測不可能性や再現不可能性を持たせます。組み込み開発においても、多くの評価ボードにはRNGとよばれるハードウェアとしての乱数発生器がついていることも多いです。
　また余談になりますが、完全にソフトウェアのみで生成する擬似乱数生成器と呼ばれるものも使われたりしています。ただし、擬似乱数生成器の中でも、Cの標準ライブラリで使用されている線形合同法による乱数生成は周期を持ってしまうため、暗号技術には適さないので注意が必要です。一方向ハッシュ関数や暗号化を用いた擬似乱数生成器等、予測不可能性があるものを使用しましょう。

# 参考文献

- 暗号技術入門 秘密の国のアリス(書籍)
https://cr.hyuki.net/ 

- その他参考サイト
https://www.cloudflare.com/ja-jp/learning/ssl/how-does-ssl-work/
https://www.cloudflare.com/ja-jp/learning/ssl/what-happens-in-a-tls-handshake/
https://jp.tenable.com/plugins/nessus/156899
https://developer.mozilla.org/ja/docs/Glossary/Cipher_suite