# 暗号技術入門

アリスとボブ

バージョン： 2.1

本ガイドの最終更新： 2022-08-11

ガイド一覧に戻る — Markdown | HTML

1. 暗号とは
   1. セキュリティ特性
2. 注意点と限界
   1. 暗号は本当に適切な解決策か？
   2. 暗号機能が提供するセキュリティ特性を理解する
   3. 暗号技術の安全性を確認する
   4. 暗号解読
   5. 自分の秘密鍵を自分で保管する
   6. 暗号技術は人間的攻撃に対して脆弱
   7. 不便性や使用ミスによるセキュリティリスク
3. 暗号の要素
   1. 公開鍵暗号
   2. 暗号化
   3. ハッシュ化
   4. 署名
   5. メッセージ認証符号
   6. 検証
   7. 疑似乱数生成
   8. 鍵交換
   9. 鍵導出

# 暗号とは

暗号とは、第三者や悪質な行動から情報と通信を保護する手法です。デジタルデバイスを対象にした現代の暗号は情報セキュリティ、計算科学、数学、物理学、電気電子工学、通信工学などの分野を交差し、商業、通貨、人権保護、軍事、身元のデジタル化などの用途に使われています。通信だけに限らず、記憶媒体にデータを保存する際にも適用できます。

情報の所在・存在を隠すことを目的にするステガノグラフィや物質的手法と異なり、暗号は情報の所在・存在を隠さずに情報を第三者が読めないようにすることが多いです。

## セキュリティ特性

現代の暗号はただ秘匿性だけでなく、使用事例に適した様々なセキュリティ特性を実現できます。以下では暗号で実現できるセキュリティ特性の例を大きく分類します。

- 秘匿性（confidentiality）：情報・通信を読めないようにすること（盗聴防止）。
- 完全性（integrity）：データが変化していないと検証すること（破損・改竄の検出）。
- 認証性（authenticity）：人の資格やメッセージの出所を検証すること（なりすまし防止）。
- 匿名性（anonymity）：身元を特定したり候補を絞ったりできないようにすること（身元特定防止）。
- 否認不可性（non-repudiability）：行為・事実を否認できないようにすること。
- 否認可能性（deniability）：行為・事実を否認できるようにすること。

これらのセキュリティ特性は互いに密接な関係があることが少なくありません。例えば、通信において、相手を認証しなければ、相手が思っている人でなく悪質な他人かもしれず、通信が盗聴されてしまいます。否認不可性と否認可能性は名称と定義どおり対立する特性です。また、使用事例によって認証と匿名性を同時に得る・実現することが不可能または困難かもしれません。

これらのセキュリティ特性にはニュアンスがあって、それを理解することが重要です。例えば、秘匿性に関して、情報を第三者から保護すべきか当事者からも保護すべきか、一連のメッセージのうちの一通を復号化できればその一連のメッセージを全て復号化できるべきか復号化できないべきか、など、様々な差異があり、使用事例によってどのような秘匿性が必要かが異なります。もちろん、暗号の強度、暗号を実装したコードの品質、ハードウェアの安全性などによって、セキュリティ特性の強度が異なります。

# 注意点と限界

暗号は強力なツールだが、万能の対策でも魔法でもありません。暗号を信用・利用する前に、以下の点を考慮した方がいいでしょう。

## 暗号は本当に適切な解決策か？

「デジタルセキュリティの概念」では、自分の状況を理解すること、最弱点から対策を始めること、 KISS 原則、記録した情報を最低限することなど様々な原則を推奨しました。あなたの使用事例に暗号は本当に最適な解決策か、それとも、ローテクの対策または情報隠蔽の方が適切か？状況によって異なります。ハイテクな対策にこだわらずに、他に適切な対策を考えてみてください。

→ ガイド：デジタルセキュリティの概念 § KISS：単純な対策を優先する — Markdown | HTML

## 暗号機能が提供するセキュリティ特性を理解する

暗号機能を採用する前に、提供されるセキュリティ特性の詳細を理解することが重要です。

「暗号化メール」は具体的にどんな暗号化なのか不明すぎるため、秘匿性の強度、どんな敵から情報を保護してくれるかが不明です。トランスポート暗号化、サーバのディスク暗号化またはエンドツーエンド暗号化がメールに適用されるかによって、「暗号化メール」が提供してくれる秘匿性が異なります。

署名を行う際、署名者が決めたメッセージだけでなく、署名日時（タイムスタンプ）、署名者情報、アプリケーションバージョンなど他の情報もアプリケーションによって含まれることが少なくありません。署名を検証する時にどの情報が署名で保護されているか、そして署名を行う際に他にどの情報が追加（漏洩）されるか、それらを理解した方がいいでしょう。

通信のメタデータ（データについてのデータ）が暗号で保護されない場合が多いです。例えば、ウェブ閲覧の際、ウェブサーバとのやり取り（内容）がしばしば TLS で保護されるが、 IP （インターネットプロトコル）ではトラフィックの IP アドレスが平文のままです。

OpenPGP の署名や暗号化はメールの内容の保護に利用できるが、メールの宛先、送信元、件名などを保護しません。また、メールのメッセージが OpenPGP で署名されても、署名者がメールを送ったとの認証になりません。

→ ガイド： OpenPGP と GnuPG § メタデータをほぼ全く保護しない — Markdown | HTML

虚偽宣伝をするソフトウェアプロジェクトやサービス提供者もいるので、セキュリティ特性をできる限り理解してから採用することを推奨します。例えば、エンドツーエンド暗号化を提供すると偽ったビデオ通話ソフトが自らのサーバで会話を傍聴できる方式だった事例がありました。

→ 外部資料： Zoom E2EE の虚偽宣伝： `https://theintercept.com/2020/03/31/zoom-meeting-encryption`

→ ガイド：デジタルセキュリティの概念 § 物事を疑わずに受け入れず、十分に検証する — Markdown | HTML

## 暗号技術の安全性を確認する

暗号機能のセキュリティ特性を理解することが良いスタートだが、そのセキュリティ特性を実現する暗号技術は本当に安全でしょうか？

解読攻撃の知識によって暗号アルゴリズムは時間につれて弱体化する可能性があり、設計時にバックドアが施された可能性もあります。また、暗号機能には実装上のバグ、バックドア、サイドチャネルなどの脆弱性が入っている可能性があります。 NSA のバックドアが入っていると広く疑われている Dual_EC_DRBG 疑似乱数生成アルゴリズムが代表的な例です。

→ 外部資料： Dual_EC_DRBG： `https://www.wdic.org/w/WDIC/Dual_EC_DRBG`

→ 外部資料： SafeCurves （推奨の楕円曲線）： `https://safecurves.cr.yp.to/`

暗号アルゴリズム以外の技術的な問題も存在する場合があります。古いシステムへの後方互換性を維持しようとする暗号技術はたいていダウングレード攻撃1に対して脆弱です。以下のようなダウングレード攻撃に対する脆弱性の例をあげます。

- 日和見暗号化2または他にセキュリティ機能が強制されない技術：不便性または使用ミスによる無効化、 MITM 攻撃3による通信セキュリティの無効化。（例： HTTPS や STARTTLS における非暗号化通信への格下げ、 OpenSSL における古いバージョンの TLS への格下げ）
- 技術の脆弱なアルゴリズムへの対応による危険動作。（例： OpenPGP や SSH のバックドア楕円曲線や SHA-1 ハッシュ関数への対応）

FLOSS （自由オープンソースソフトウェア）や FLOSH （自由オープンソースハードウェア）は安全性の確認可能性には不可欠です。開発者以外の人たちがソフトウェアやハードウェアのソースコードを閲覧・確認できなければ、安全性の確認は不可能なため、信用不可能です。

→ ガイド：デジタルセキュリティの概念 § FLOSS を使用する — Markdown | HTML

利用者全員がこの確認をしなければならないわけでなく、専門者でない一般の利用者にとって確認作業が無理または困難でしょう。しかし、開発者から独立した専門者によるセキュリティ監査の報告書、コミュニティ掲示板の投稿、他の情報などを参考にしながら、利用者には少なくとも安全なアルゴリズムと実装が使われているかを確認してから暗号機能を採用することを推奨します。

### 自家製暗号に要注意

“Don’t roll your own crypto” （自家製暗号を開発するな）という注意スローガンがよくあります。暗号学とプログラミングとデジタルセキュリティに精通していない人たちが開発したコード、一人だけが開発したコード、セキュリティの議論・レビュー・監査が不十分なコードなどは、実際使用の際に要注意です。

暗号学とプログラミングとデジタルセキュリティに精通していない限り、実際使用用の暗号を自分で設計・実装しようとしないでください。アルゴリズム誤選択、アルゴリズム実装ミス、サイドチャネル攻撃4、ソフトウェア脆弱性、ユーザエクスペリエンス上の問題など多くの罠があります。

→ 外部資料：自家製暗号に関連する罠と注意点： `https://loup-vaillant.fr/articles/rolling-your-own-crypto`

開発しているソフトウェアに暗号を採用する必要がある場合、既存の高品質のライブラリを探して採用することを推奨します。

→ 外部資料：暗号ライブラリの比較： `https://ja.wikipedia.org/wiki/暗号ライブラリの比較`

## 暗号解読

暗号解読（cryptanalysis）とは、暗号のアルゴリズム上または実装上の弱点を探すことです。秘密情報（例：鍵、パスワード、平文）を使用せずに以下のようなことが攻撃者にとって主な目的です。

- 暗号化で作成した暗号文からの平文の入手
- ハッシュ値からの元のメッセージの入手
- 署名の偽造
- CSPRNG 出力の予測
- 暗号プロトコルの迂回

暗号解読の範囲は、すべてのメッセージまたは鍵の候補を試行した総当たり攻撃5より簡単な暗号攻撃を指し、サイドチャネル攻撃を含みます。一方、アルゴリズム実装ミス、ハードウェア上の脆弱性、人間的攻撃などという暗号自体以外に対する攻撃を除きます。

暗号解読の研究が進むにつれて、暗号技術の脆弱性が判明されます。例えば、量子コンピュータが強くなった時代になったら量子計算への耐性がない暗号アルゴリズムが脆弱になってしまいます。現実的に脆弱だと判断された暗号技術の使用を避け、必要に応じて暗号技術を更新することを推奨します。

まだ脆弱でない暗号も時代につれて脆弱になるかもしれません。注意すべきことは、現在に存在する暗号文やハッシュ値は未来に解読される可能性があります。未来時の解読のために暗号文、ハッシュ値、署名などを収集する攻撃者から暗号は情報を十分に保護してくれないかもしれません。そのため、未来に明かされたら被害が生じるかもしれないセンシティブ情報や秘密鍵から導出した暗号文、ハッシュ値、署名などもできる限り安全に保管したり流出を防いだりすることを推奨します。

## 自分の秘密鍵を自分で保管する

自分の秘密鍵を独占的かつ安全に保管することは非常に重要な原則です。自分の秘密鍵が他人の手に入ると、その他人が自分に暗号されたメッセージを盗聴したり自分をなりすましたり、自分の暗号通貨を移動させたりできてしまいます。また、自分で秘密鍵を保管せず、他人に秘密鍵を任せると、自分が自分の秘密鍵へ自由にアクセスできなくなることもあります。このように秘密鍵がアクセス不可になるか流出すると、事後対策が大変で完全な回復が不可能な場合が多いです。

近年、暗号の利用が増え、それに伴って、暗号を使用する様々なサービスが誕生しました。例えば、暗号化電子メール、 OpenPGP 鍵を扱うソーシャルネットワーク、暗号通貨取引所などがあります。しかし、このようなサービスは利用者の秘密鍵を保管することが多いです。サービス提供者が利用者の秘密鍵を保管している場合、サービス提供者が勝手に利用者のメールを勝手に読んだり利用者の暗号通貨を勝手に使ったりすることができます。また、利用者自身が秘密鍵を保管していない場合、サービス提供者が利用者に秘密鍵を渡すことを拒むと利用者が自分のメールや暗号通貨にアクセスできなくなってしまいます。要するに、利用者が秘密鍵を独占的に保管しながらサービスを利用し、それが不可能なサービスを慎重に使うことを推奨します。

個人データをバックアップする際、秘密鍵を不意に平文のままでバックアップしたり他人に渡したりしないよう気をつけてください。特に、オンラインのサービスへの自動バックアップを慎重に使うべきです。

秘密鍵といえば、 OpenPGP の秘密鍵、暗号通貨ウォレットの復元用シード、 Session メッセンジャーのシードなどの長期鍵類はもちろん、パスワードやセッション鍵にも同じ原則が当てはまります。

## 暗号技術は人間的攻撃に対して脆弱

セキュリティは単に技術的な課題だけでなく、人間や社会にも密接な関係がある課題です。暗号技術自体が暗号的または計算的な攻撃を受けても丈夫だとしても、利用者に対する詐欺や強要などという人間的攻撃によって情報、通信、デバイス、アカウントなどが危殆化するおそれがあります。また、ソフトウェアやハードウェアの開発者やサービス提供者は製品・サービスの危殆化を目的とした攻撃者に狙われるかもしれません。

暗号技術の単なる使用ミスを除いて、人間的攻撃はだいたい以下の種類に大別できます。

- 働きかけ（例：賄賂、扇動、誘惑）
- ソーシャルエンジニアリング（social engineering）（例：フィッシング、詐称、トロイの木馬、共連れ）
- 強要（例：法的義務、脅迫、拷問）

以下の状況に置かれている場合、用心した方がいいでしょう。

- データ漏洩の被害者になった。
- 自分の活動を妨げようとしている敵対者がいる。（例：ジャーナリスト、弁護士、活動家、内部告発者）
- パスワード、秘密鍵、アカウント情報、データなどの譲渡またはデバイス捜索が強要されるリスクが高い。（例：令状なしの捜索がある地域、国境を越える渡航）
- 暗号技術の入手・所持・利用・提供が犯罪扱いされる地域に滞在・居住している。
- 技術の開発・提供をしている企業で働いている。

→ 外部資料：暗号の使用・輸入・輸出に関連する法律： `https://web.archive.org/web/http://www.cryptolaw.org/`

## 不便性や使用ミスによるセキュリティリスク

人間的攻撃について前述したが、攻撃者がいなくても暗号技術の不便性や使用ミスによって情報を流出したり脆弱性を作ったりしてしまうおそれがあります。

利用者が暗号またはアプリケーションを理解していない、暗号ツールのユーザインターフェイスや複雑さの問題のため誤操作される、暗号機能が任意な場合に有効化が忘れられる、という使用ミスの原因がよくあります。

以下に暗号技術に関する使用ミスの例をいくつかあげます。

- 入手した公開鍵を信頼する他人の鍵だと思い込んで使用する。
- 情報の暗号化を忘れるか暗号化が失敗する。
- 危殆化された公開鍵または違う公開鍵で情報を暗号化する。
- 暗号化を使用しながら情報を違う人または宛先に送信する。
- 鍵・パスワードを紛失したため暗号文を復号化できなくなる。
- 暗号化が不便なため無効化を選択する。
- 当事者の間に安全なチャネルと安全でないチャネルが両方ある場合、不意に情報を安全でないチャネルで送る。

以上の例と利用者の多様性を考えると、間違えようのない暗号ツールが重要であることがわかるでしょう。暗号ツールの単なる理論的セキュリティより、利用者や社会環境を含めて実際の使用事例について考えることが重要です。

# 暗号の要素

本セクションでは暗号の利用に役立つ暗号の要素について説明します。まず、以下の用語を簡潔に説明します。

暗号プリミティブ（cryptographic primitive）とは、暗号プロトコルや暗号系の構築に用いられる基本要素です。高度の信頼性がある暗号プリミティブはシステム構築に必要不可欠です。

暗号アルゴリズム（cryptographic algorithm）とは、ある暗号機能と実現するアルゴリズム（算法）です。

暗号方式、暗号システムまたは暗号系（cryptosystem）とは、一連のセキュリティ特性を実現するために構築されたシステムで、一連の暗号アルゴリズムを含むシステムです。たいていは鍵生成、暗号化と復号化のアルゴリズムを含むシステムを指します。

暗号プロトコル（cryptographic protocol）とは、暗号を用いてセキュリティ機能を実現する通信プロトコルです。たいていは実際に通信に利用する暗号方式を指すが、通信以外の使用事例にも役立つかもしれません。

## 公開鍵暗号

他の要素を説明する前に、まず公開鍵暗号を簡潔に説明しておきます。

公開鍵暗号（public key cryptography）または非対称暗号（asymmetric cryptography）とは、数学的に関係づけられた公開鍵と秘密鍵を用いた暗号です。秘密鍵から公開鍵を簡単に導出できるが、その逆が困難であるような数学的関係を有します。公開鍵が使われることから「公開鍵暗号」の名称が由来し、暗号化と復号化（または署名と検証）の際に異なる鍵を使うことから「非対称暗号」の名称が由来します。

数学的に関係づけられた公開鍵と秘密鍵は鍵ペアまたは鍵対（keypair）と呼びます。

公開鍵は、名称どおり、公開しても問題がありません。公開鍵を持っている人は秘密鍵所有者宛に秘密を送ったり秘密鍵所有者が署名したデータを検証したりできます。

一方、秘密鍵を安全に保管する必要があります。秘密鍵が流出すれば、その鍵を入手する他人は対応する公開鍵宛に暗号化した全てのメッセージを読んだり本来の秘密鍵所有者をなりすましたりできるようになってしまいます。

以下は公開鍵暗号アルゴリズムの代表例です。

- RSA
- 楕円曲線（ECC）
  - Ed25519 （署名）
  - Curve25519 （X25519 ECDH 鍵交換）

→ 外部資料： RSA 暗号： `https://invidious.snopyta.org/watch?v=HKDyUELFdXs`

→ 外部資料：楕円曲線暗号： `https://invidious.snopyta.org/watch?v=jxmN8LqyTR4`

## 暗号化

暗号化（encryption）とは、鍵（公開鍵、パスワードなど）を用いてある情報を読めないようにすることで、秘匿性を実現する手法です。暗号化された情報は「暗号文」（ciphertext）と呼ばれ、もとの情報は「平文」（ひらぶん、 plaintext）または「明文」（cleartext）と呼ばれます。暗号化は、鍵を用いて平文を暗号文に変換する行為です。復号化（decryption）は暗号化の逆で、秘密の鍵（秘密鍵、パスワードなど）を用いて暗号文を平文に戻す行為です。

情報を読めないようにする対象は一般的には第三者（当事者以外）だけだが、当事者（例えば情報を暗号化した人自身）も情報を読めないようにする使用事例もあります。

暗号化には種類があります。

### 暗号化のプリミティブ

#### 対称鍵暗号化

対称鍵暗号化（symmetric encryption）または共通鍵暗号化（common key encryption）とは、暗号化と復号化に共通する鍵（共通鍵）を用いた暗号化です。対称鍵暗号化アルゴリズムはサイファ（cipher）とも呼ばれます。

- ブロックサイファ（block cipher）：ブロック単位（例： 128 ビット）の情報を読み込んで暗号化する。
- ストリームサイファ（stream cipher）：小さな単位（例： 1 バイト）の情報でも次々に暗号化できる。

対称鍵暗号化は、公開鍵暗号化より高速で、サイファの実行に適したハードウェアがあります。保存したい情報の暗号化などという通信以外の使用事例に適しています。

しかし、共通鍵をどうやって通信相手に安全に渡すかという問題があり、通信相手との安全な通信チャネルが既に存在しない場合に使えません。仮に対称鍵暗号化だけで秘匿通信を実施する場合、各通信チャネルに別個の秘密鍵が必要となるため、各当事者が相手の数の秘密鍵を交換・保管しなければなりません。このシナリオでは、通信網の規模を拡張することが困難で、ミスと情報流出が発生する可能性が高すぎます。

以下は対称鍵暗号化アルゴリズムの代表例です。

- ブロックサイファ：
  - AES
- ストリームサイファ：
  - ChaCha と Salsa20

#### 公開鍵暗号化

暗号化と復号化に共通する鍵を用いた暗号化と異なり、公開鍵暗号化（public key encryption）または非対称鍵暗号化（asymmetric encryption）とは、公開鍵を用いた暗号化のことです。公開鍵で暗号化したメッセージを、数学的に関係づけられた秘密鍵を用いて復号化します。

公開鍵暗号化では、鍵がデジタル身元の役割を果たすことが多く、簡単に長期的に同じ鍵ペアを利用することができます。通信に必要な秘密情報について、各当事者が自分の鍵ペアだけを交換・保管する必要があります。

しかし、公開鍵暗号化は対称鍵暗号化より遅いため、大量の情報の暗号化に適していません。また、公開鍵を多く使用すると秘密鍵の情報が徐々に漏洩される可能性があります。

#### ハイブリッド暗号化

ハイブリッド暗号化（hybrid encryption）とは、公開鍵暗号化と対称鍵暗号化を組み合わせた暗号化のことです。公開鍵暗号化と対称鍵暗号化と異なり、ただの暗号化プリミティブではなく、プリミティブを組み合わせた物です。

ハイブリッド暗号化は公開鍵暗号化と対称鍵暗号化の両者のメリットを取り入れながらデメリットを排除しようとします。対称鍵暗号化は公開鍵暗号化より高速で大量情報の暗号化に適している一方、公開鍵暗号化は安全なセッション鍵（session key）の共有に適しています。公開鍵は長期的に使用できるデジタル身元みたいなものです。

ハイブリッド暗号化の一例は、一通のメッセージだけに使うセッション鍵を生成してから公開鍵で暗号化し、メッセージをセッション鍵とサイファで暗号化する仕組みです。 OpenPGP はこのようなハイブリッド暗号化を使います。他に、身元鍵（identity key）の役割を演じる公開鍵が危殆化されてもセッション鍵が危殆化されない前方秘匿性のある通信方式など、様々なハイブリッド暗号化もあります。 TLS と SSH もハイブリッド暗号化を使います。

→ ガイド： OpenPGP と GnuPG § 暗号化 — Markdown | HTML

### 暗号化技術の種類

暗号化のプリミティブについて前述しました。ここで用途で分類した暗号化について紹介します。

#### 保管時の暗号化

保管時の暗号化（encryption at rest）とは、情報を保管する際の暗号化です。暗号化ファイルシステムを利用したら、ファイルシステムに保存する情報の暗号化・復号化が自動的です。自分のデバイス上に情報を保存するには不可欠な暗号化です。

OpenPGP （秘密鍵やメッセージの暗号化）、 KeePassXC （データベースの暗号化）、 LUKS （ファイルシステムの暗号化）、 VeraCrypt （ファイルシステムの暗号化）などのアプリケーションは保管時の暗号化を活用します。

しかし、他人のデバイスに情報を任せる場合、保管時の暗号化の価値が少ないでしょう。保管先が暗号化の鍵も持っている場合、保管先が勝手に情報を覗き見・改竄できます。また、情報をネットワーク経由で保管先にアップロード・ダウンロードする場合、保管先との間の通信を保護しなければ第三者が通信を傍受するリスクがあります。通信を保護した上で行うよう注意し、保管先も情報を復号化できないようなエンドツーエンド暗号化を利用した方がいいかもしれません。

#### 転送中の暗号化

転送中の暗号化（encryption in transit）またはトランスポート暗号化（transport encryption）とは、情報が転送中に秘匿性を保護するよう、送信者から受信者まで施す暗号化です。例えば、 SSL/TLS は過去 10 年の間に徐々に採用され、現在はほとんどのウェブサイトが TLS に対応しているため、インターネットに重大なセキュリティ向上に貢献しています。

転送中の暗号化は、送信者と受信者の間に転送される情報を復号化して再び暗号化する方式も含みます。情報の復号化・再暗号化をする中間者が存在する場合、その情報が転送中に盗聴・改竄される可能性があります。また、エンドツーエンド暗号化と異なり、当事者が鍵の交換・検証を十分に行えない場合が多いです。そのため、秘匿性と認証が重要な使用事例には転送中の暗号化だけに頼ってはならず、エンドツーエンド暗号化を利用した方がいいかもしれません。

#### エンドツーエンド暗号化

エンドツーエンド暗号化（end-to-end encryption、 E2EE、 E2E 暗号化）とは、送信者と受信者で構成される当事者（エンドポイント）だけが鍵を持ち、中間者や第三者による傍聴を防ぐ暗号化です。単の転送中の暗号化と異なり、当事者が各自鍵ペアを生成・管理・交換したりセッション鍵に合意したりし、当事者だけがコントロールする暗号で通信を保護します。

エンドツーエンド暗号化は Tor オニオンサービス、 OpenPGP、 Signal プロトコルまたはそれに類するプロトコルのメッセンジャーなどに活用されています。

## ハッシュ化

ハッシュ化（hashing）とは、任意長のメッセージ（原像、 pre-image）を決定的に固定長の数値に写像する手法です。出力値はハッシュ値（hash）またはダイジェスト（digest）と呼ばれます。写像自体はハッシュ関数（hash function）と呼ばれます。

ハッシュ化のなだれ効果。
メッセージ | SHA-256 ハッシュ値 | 備考
--- | --- | ---
`Hello world!` | `c0535e4b...1ad9e51a` | 参考例。
`hello world!` | `7509e5bd...e08e6ca9` | `H` を小文字 `h` に変換した。
`Hello world.` | `aa3ec16e...bd115d11` | `!` を `.` に置き換えた。
`Hello world` | `64ec88ca...eca37f3c` | `!` を削除した。

ハッシュ化は決定的な計算で、同じメッセージに対して同じハッシュ値が得られます。しかし、ハッシュ化にはなだれ効果（avalanche effect）があり、メッセージが微小に変化してもハッシュ値が全く変わります。

可逆性のある暗号化・復号化と異なり、ハッシュ化は不可逆な変換で、メッセージを復元する逆演算がありません。また、暗号に適した安全なハッシュ関数（暗号的ハッシュ関数、 cryptographic hash function）に求められる性質は以下です。

- 決定性（determinism）：同じメッセージをハッシュ化したら同じハッシュ値を得ること。
- 無作為性（randomness）：メッセージが極わずかでも変化したら全く違うハッシュ値を得ること。
- 原像計算困難性（pre-image resistance）：
  - 第 1 原像計算困難性：与えられたハッシュ値を有するメッセージを探すことが困難であること。
  - 第 2 原像計算困難性：与えられたメッセージと同じハッシュ値を有する別のメッセージを探すことが困難であること（弱衝突耐性）。
- 衝突耐性（collision resistance）：同じハッシュ値を有する異なるメッセージを探し出すことが困難であること（強衝突耐性）。

情報の完全性検証に大きな役割を演じます。ある情報の正しいハッシュ値を持っていれば、情報をハッシュ化した結果と照合することで完全性を確認できます。様々な使用事例があります。

- 入手したソフトウェアや他の情報の完全性確認：ソフトウェア提供者がリリースのハッシュ値を公開する場合、ソフトウェア入手者がそれを用いてダウンロードを確認できる。
- 自分のデバイス上のデータの破損・改竄の検出：すべての各ファイルのハッシュ値を保管すれば、後で各ファイルの完全性を確認できる。
- サーバ上のアカウントのパスワード保護：サーバがパスワードの平文ではなくハッシュ値を保存することで、アカウントへのログインを可能にしながらも、パスワード流出からアカウントを（多少）保護する。（ハッシュ化だけでのパスワード保護を推奨しません）

ただし、ハッシュ化は認証を提供せず、正しいと確認されていないハッシュ値だと攻撃者がハッシュ値を改竄・提供したリスクがあります。認証を得るには、署名または MAC または他の認証手段が必要です。

以下はハッシュ関数の例です。

- BLAKE2
  - BLAKE2S
  - BLAKE2B （`b2sum`）
- BLAKE3
- SHA2 （`shasum`）
  - SHA-256 （`sha256sum`）
  - SHA-512 （`sha512sum`）
- SHA3

コマンドライン上のハッシュ関数の使用例を以下に紹介します。

    $ # 文字列を SHA-256 でハッシュ化。
    $ # 注： echo が後尾に改行を付加しないよう -n フラグを追加。
    $ echo -n 'Hello world!' | sha256sum
    c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a  -
    $ # ファイルの内容を SHA-256 でハッシュ化して SHA256SUMS に書き込む。
    $ sha256sum alice.txt | tee SHA256SUMS
    e0c9d974fa7728f510af0e1f8610a880c6bcc069b3902fd3e8b3c33a8f0f780b  alice.txt
    $ # SHA-256 ハッシュ値を照合。
    $ sha256sum --check SHA256SUMS
    alice.txt: OK

## 署名

署名（signing）とは、秘密鍵を用いてメッセージの完全性と認証を検証可能にする証明の生成のことです。署名アルゴリズムが出力する検証のための情報は署名（signature）と呼ばれます。秘密鍵で署名されたメッセージと署名を、数学的に関係づけられた公開鍵を用いて検証します。

署名されたメッセージの検証に成功したら、検証者が暗号上正当なメッセージと署名と公開鍵を揃って所有するため、以下のことを証明できます。

- 完全性：検証者が所有するメッセージと署名されたメッセージが一致すること。
- 認証性：検証に用いた公開鍵に対応する秘密鍵の所有者がメッセージに署名したこと。
- 否認不可性：暗号上、秘密鍵の所有者がメッセージに署名したことを否認できないこと。

このような特性を持つため、契約や注文など重要な文書に署名するという応用例に適しています。また、リリースしたソフトウェアに署名するソフトウェア開発者が少なくありません。

ハイブリッド暗号化と似ているように、現代の署名は公開鍵暗号とハッシュの両者のメリットを取り入れながらデメリットを削減し、メッセージへの直接の署名ではなく、メッセージのハッシュ値に対して秘密鍵を用いて署名アルゴリズムを適用します。

## メッセージ認証符号

メッセージ認証符号（message authentication code、 MAC）とは、共通鍵と任意長のメッセージを入力とするアルゴリズムで生成された、メッセージを検証する際に使う情報です。 MAC はメッセージの完全性確認を可能にし、メッセージの共通鍵を所有する検証者に送信者からのメッセージであることを証明します。

検証に成功したメッセージと MAC で、以下を得ます。

- 完全性：検証者が所有するメッセージと MAC で保護されたメッセージが一致すること。
- 認証：検証に用いた共通鍵の所有者のうちの誰かが作成・送信したメッセージであること。

署名と異なり、 MAC はメッセージの共通鍵を用いるため、送信者がメッセージを作成・送信したという暗号上証明になりません。共通鍵を知っている受信者がメッセージを作成して MAC を生成した可能性が残ります。

以下は MAC アルゴリズムの例です。

- HMAC （hash-based MAC）：
  - HMAC-SHA256
  - …
- Poly1305：
  - Poly1305-AES
  - Poly1305-ChaCha20 と Poly1305-Salsa20

## 検証

署名と MAC について前述したため、ここで検証について簡潔に説明します。

暗号における検証（verification）とは、情報の完全性・出所や通信相手の身元などを確認することです。与えられた情報（メッセージ、ハッシュ値、署名、公開鍵、 MAC、共通鍵など）から以下の結果が出ることが可能です。

- エラー（error）：与えられた情報に不備があった場合。
- 拒否（rejected）：与えられた情報の整合性を確定できなかった場合。
- 承認（approved）：与えられた情報の整合性を確定した場合。

## 疑似乱数生成

疑似乱数生成器（pseudo-random number generator、 PRNG）は、疑似乱数列を出力するアルゴリズムです。暗号的に安全な PRNG （cryptographically secure PRNG、 CSPRNG）は、強力な秘密鍵、セッション鍵、ソルト、パスワードなどを生成するために不可欠な要素で、暗号方式が多く CSPRNG を活用します。

PRNG はシード値（seed）と呼ばれる乱数で初期化されてから使用されます。 PRNG の出力は決定的で、同じシード値を与えたら同じ数列が出力されます。 PRNG の内部状態またはシード値が知られたら、出力が予測可能になってしまいます。そのため、暗号やセキュリティの使用事例では CSPRNG が安全に初期化される必要があります。

真の乱数列は規則性も再現性もなく、予測不可能です。一方、 PRNG の出力は真の乱数列ではありません。 PRNG の出力が真の乱数列に近似するには、良い統計的無作為性（一様性、無相関など）が必要です。それに加えて、 CSPRNG は出力を予測する攻撃への耐性も有します。

以下は疑似乱数生成アルゴリズムの例です。

- arc4random
- Fortuna （`/dev/urandom` によく使われている）

コマンドライン上の疑似乱数の使用例を以下に紹介します。

    $ # 8 バイトの疑似乱数をバイナリ形式のままでファイルに書き込む。
    $ head -c 8 /dev/urandom > random.txt
    $ # 32 文字の base64 形式の無作為文字列を生成。
    $ cat /dev/urandom | base64 --wrap=0 | head -c 32
    zsOGDz9q3zQ6mJk8dLQKvZcPTF+lxk9t
    $ # 小文字と数字だけの 10 文字の無作為文字列を生成。
    $ cat /dev/urandom | tr -dc 'a-z0-9' | head -c 10
    lenjiqlnfi

## 鍵交換

鍵交換（key exchange）とは、通信の当事者が秘密の共通鍵に合意する手法です。

非暗号化チャネル上で秘密情報や鍵を平文で送信すると、それが盗聴されるおそれがあるため、非暗号化チャネル上で通信を行う前にまず共通鍵に合意する必要があります。仮に非暗号化チャネル上で使える安全な鍵交換手段がなかった場合、まず事前に当事者が面会して鍵を交換するか安全な他のチャネル（例：信用たる宅配便業者）で鍵を伝える必要があります。

ところが、 Diffie–Hellman 鍵交換法では監視されている非暗号化チャネル上でも当事者が安全に秘密の共通鍵に合意できます。当事者が共通鍵に合意した後、対称鍵暗号化を用いた秘匿通信ができます。ただし、認証性のあるチャネルまたは他の認証手段が必要です。何かしらの認証を行わない場合、 Diffie–Hellman 鍵交換はチャネル上のメッセージを改竄できる MITM 攻撃に対して失敗します。

### 前方秘匿性

前方秘匿性（forward secrecy）は、鍵交換に使用した長期的な鍵（例：鍵ペア）が危殆化されてもセッション鍵が危殆化されないという暗号化の仕組みです。前方秘匿通信では各セッションに新しい鍵が生成・使用されるため、一つのセッションが危殆化されても他のセッションに及びません。

鍵生成が速い Diffie–Hellman 鍵交換は前方秘匿性の実現によく使われます。メッセージのやり取りの使用事例では、メッセージ毎に鍵交換を行うことによって前方秘匿性を実現できます。

## 鍵導出

鍵導出（key derivation）とは、秘密情報（パスワードまたは身元鍵など）を用いて、特定の形式を満たす鍵、強力な鍵、複数の鍵などを導出することです。以下の目的に使用されます。

- 特定の形式を満たす鍵：パスワードや鍵長が合わない鍵などから希望の形式・鍵長の秘密鍵を導出。（例：パスワードから 256 ビットの鍵を導出）
- 秘密情報を得ようとする攻撃に耐える鍵：弱いかもしれない秘密情報（例：短い鍵）から秘密情報を得ようとする攻撃に耐える鍵を導出。鍵ストレッチングと呼ばれる。
- 複数の鍵：秘密でない情報を付加したりハッシュ化を繰り返したりすることで、同じ秘密情報から複数の鍵を導出。

鍵導出は疑似乱数関数（pseudo-random function）を利用し、たいていはハッシュ関数またはブロックサイファを疑似乱数関数として利用します。鍵導出は決定的でありながら、秘密情報（またはソルト）が変わるとなだれ効果によって全く違う鍵が得られます。

以下は鍵導出関数の例です。

- Argon2
- bcrypt
- PBKDF2
- s2k （OpenPGP）
- scrypt

### ソルト化

ハッシュ値 = SHA256(パスワード) （ソルト化なし）。
ユーザ名 | パスワード*1 | ハッシュ値
--- | --- | ---
`alice` | `helloworld` | 0x936a185c…
`bob` | `helloworld` | 0x936a185c…

ハッシュ値 = SHA256(パスワード+ソルト値) でのソルト化。
ユーザ名 | パスワード*1 | ソルト値*2 | ハッシュ値
--- | --- | --- | ---
`alice` | `helloworld` | 0xa8e09915 | 0xd95f96f4…
`bob` | `helloworld` | 0x9a0bcd84 | 0x88fb566e…

- *1：アカウントのパスワードをサーバ上に保存しない。
- *2：実際には 32 ビットより長い値を使うべき。

鍵導出にはソルト値（塩、 salt）という乱数が与えられることがあります。秘密情報にソルト値を付加してからハッシュ化すると、秘密情報が同じであっても毎回異なるハッシュ値が得られます。

ソルト値とハッシュ値が流出しても、秘密情報を得ようとする攻撃からその秘密情報を保護します。保存されているパスワードの保護によく活用されます。ソルト化することで、以下のセキュリティメリットが得られます。

- レインボーテーブルの事前算出が実行不可能になるため、レインボーテーブル6を用いた攻撃からパスワードを保護する（ただし、弱いパスワードを保護しない）。
- 同じパスワードを使うアカウントのハッシュ値が一致しなくなるため、パスワードが複数のアカウント・サービスにわたって繰り返し使われても（例：短い文字列、パスワードの再利用）一つのアカウントの危殆化は他のアカウントに影響しない。

ただし、以上のような簡単なソルト化では、強力なオフライン攻撃7が実行できる攻撃者がソルト値とハッシュ値を入手した場合、保護が不十分かもしれません。また、辞書攻撃8からの保護が限定的です。

### 鍵ストレッチング

鍵ストレッチング（key stretching）とは、弱いかもしれない秘密情報（例：人間が発想したパスワード、短い鍵）から攻撃に耐性のある鍵を導出することです。

鍵ストレッチングではソルト値が導出された鍵と共に保管される一方、鍵強化（key strengthening）ではソルト値が破棄されます。鍵強化は弱いかもしれない秘密情報から鍵を導出するが、二度と同じ秘密情報から同じ鍵を導出する必要がない用途にしか使えず、一般のパスワード保護には適しません。

ハッシュ化には高速なハッシュ関数が望ましい使用事例が多い一方、鍵ストレッチングでは攻撃を遅らせることが目的で、逆に資源（時間と空間）が多くかかる計算が望ましいです。一回だけ正しいパスワードを入力することが多い正当な利用者にとって負担がわずかな一方、多数のパスワードの候補を試行する攻撃者にとって負担が大きいという良好な非対称があります。

ソルト化とハッシュ化を（数万回〜数億回）繰り返すことで、総当たり攻撃、レインボーテーブルを用いた攻撃、辞書攻撃などのオフライン攻撃を困難または実行不可能にすることができます。例えば、 OpenPGP は最大 65,011,712 回のソルト化とハッシュ化をする鍵ストレッチング（s2k）で秘密鍵と暗号文を保護します。 LUKS ファイルシステム（デフォルト： PBKDF2）や KeepassXC データベース（デフォルト： Argon2）を解錠時、解錠に数秒ぐらいがかかることには気が付くでしょう。

1. ダウングレード攻撃（downgrade attack）：セキュリティ機能を強制しないまたは脆弱なアルゴリズムにも対応する暗号プロトコルにおける高度なモード（例：暗号化通信）から低度のモード（例：非暗号化通信）に格下げさせる攻撃。↩︎

2. 日和見暗号化（opportunistic encryption）：他のシステムに接続する際に暗号化通信を試行するものの、失敗すれば非暗号化通信を行うシステム。ほぼ常時にある程度の保護を提供しようとし、暗号化を普及させる目的で採用された事例がある。ダウングレード攻撃などの能動的攻撃や利用者にとっての不便性または使用ミスに対して脆弱。↩︎

3. MITM 攻撃（man-in-the-middle attack、 中間者攻撃）：通信において、互いに直接やり取りしていると思っている当事者の間に位置する中間者が密かに通信を中継・改竄する攻撃。 Wi-Fi ネットワーク上のハッカー、 IMSI キャッチャー、 sslstrip、悪質な公開鍵証明書認証局などは代表例。公開鍵基盤、共通秘密、相互認証、生体情報認識などの防止方法がある。ウェブサイトの訪問者とサーバの間に位置する TLS プロキシは MITM （中間者）になるためセキュリティ問題だが、 MITM 側に悪意がない限り MITM 攻撃として解釈されない。↩︎

4. サイドチャネル攻撃（side-channel attack）：システムの入出力を直接的に操作・観察せず、システムの物理的な非計画入出力（サイドチャネル）を操作・観察することで漏洩している情報を取得したり故障を注入したりする攻撃。ハードウェアの電力解析、ソフトウェア実行時のタイミング解析、 CPU クロック操作などの物理的手段でサイドチャネルを攻撃すること。↩︎

5. 総当たり攻撃（brute-force attack）：可能な秘密情報の候補を全て試みる攻撃。↩︎

6. レインボーテーブル（rainbow table）：ハッシュ値から秘密情報（例：パスワード）を解読するために、事前作成された文字列と対応するハッシュ値の計算結果の表。↩︎

7. オフライン攻撃（offline attack）：試行の回数や速度などの制限を設けるかもしれないサーバに接続してパスワードなどの候補を試みる攻撃と対照し、試行制限なしの環境において高速に候補を試みる攻撃。↩︎

8. 辞書攻撃（dictionary attack）：辞書から引いた単語、人間が発想する弱いパスワード、過去のデータ流出から得られたパスワードなどのパスワード候補を優先に攻撃を行うこと。↩︎

# アリスとボブ

ガイド一覧に戻る — Markdown | HTML

## 連絡先

### PGP 鍵

`1D3E 313C 4DB2 B3E0 8271 FC48 89BB 4CBB 9DBE 7F6D`

- ウェブサイト上： `https://git.disroot.org/alice2bob/alice2bob/src/branch/master/alice2bob.asc`
- 鍵サーバ（クリアネット）： `https://keys.openpgp.org/search?q=1D3E313C4DB2B3E08271FC4889BB4CBB9DBE7F6D`
- 鍵サーバ（オニオン）： `http://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion/search?q=1D3E313C4DB2B3E08271FC4889BB4CBB9DBE7F6D`

### ウェブサイト

`https://git.disroot.org/alice2bob/alice2bob`

## 検証

`https://git.disroot.org/alice2bob/alice2bob/src/branch/master/verify.md`

## 免責事項

アリスとボブはセキュリティ専門家でも法律家でも金融アドバイザーでも医師でもありません。本シリーズの目的はあくまでも情報提供で、何の助言でもありません。本シリーズは全くの無保証で提供されます。本シリーズによってどんな不利、損失または損害が生じても、アリスとボブは一切の責任を負いません。ご自身の状況を考慮し、自己責任で本シリーズを使ってください。