# 通知設計書 21-CryptographicException

## 概要

本ドキュメントは、VBCorLibライブラリにおける`CryptographicException`（暗号化エラー通知）の設計を定義する。この例外通知は、暗号化操作中にエラーが発生した場合にスローされ、呼び出し元に暗号処理の失敗を通知するための機構である。

### 本通知の処理概要

本通知は、VB6/.NET互換ライブラリにおける暗号化処理のエラー発生を、例外オブジェクトのスローという形で通知する。DES、TripleDES、RC2、RSA、DSAなどの暗号化アルゴリズムを使用する際、暗号キーの不正、パディングエラー、暗号サービスプロバイダー（CSP）初期化失敗、ハッシュ計算エラーなど、暗号処理固有の問題が発生した場合にこの例外が発火し、呼び出し元のエラーハンドラへエラー情報が伝播される。

**業務上の目的・背景**：セキュアなアプリケーション開発において、暗号化・復号化・ハッシュ化・デジタル署名などの暗号操作は不可欠である。CryptographicExceptionは、これらの操作中に発生するエラーを一貫した方法で通知し、セキュリティ関連の問題を明確に伝達する。Windows CryptoAPIとの連携エラーや、暗号アルゴリズム固有のエラーを包括的に表現することで、開発者が適切なエラーハンドリングを実装できるようにする。

**通知の送信タイミング**：暗号化処理の実行中にエラーが発生した時点で即座に例外がスローされる。具体的なタイミングは以下の通りである：
- 暗号化キーのインポート失敗時（CryptoAPI.ImportPlainTextKey）
- 暗号化・復号化処理の実行失敗時（CryptEncrypt/CryptDecrypt API呼び出し失敗）
- パディングの検証エラー時（不正なパディングパターン検出）
- 暗号サービスプロバイダーの初期化・取得失敗時
- ハッシュ値の計算失敗時
- RSA/DSA署名・検証処理の失敗時
- 乱数生成エラー時（RNGCryptoServiceProvider）

**通知の受信者**：例外をキャッチするエラーハンドラ（呼び出し元のVB6コード内のOn Error GoToまたはCatch系構造）。最終的には、アプリケーション開発者が設計したエラーハンドリングロジックが受信者となる。

**通知内容の概要**：例外オブジェクトには以下の情報が含まれる：
- Message：エラーの詳細説明（例：「Invalid padding.」「Could not decrypt data.」「Key cannot be weak.」）
- HResult：CORSEC_E_CRYPTO（暗号関連の標準HRESULT値）
- ErrorNumber：vbInvalidProcedureCall（5）
- Source：例外発生元のソース情報
- InnerException：原因となった内部例外（ある場合）
- Data：ユーザー定義の追加情報を格納できる辞書

**期待されるアクション**：受信者（開発者のエラーハンドラ）は以下のアクションを実行することが期待される：
1. 例外メッセージのログ出力（機密情報を含まない形で）
2. ユーザーへの適切なエラーメッセージ表示
3. 暗号化キーやパラメータの再検証・修正
4. 必要に応じてリトライ処理の実装
5. セキュリティ監査のための記録

## 通知種別

例外通知（Exception/Error通知）

本通知はVB6の例外機構（Err.Raiseおよびカスタム例外クラス）を使用したプログラム内通知であり、外部サービス（メール、SMS等）への通知ではない。Throwステートメントによって例外オブジェクトがスローされ、呼び出しスタックを遡ってエラーハンドラに到達する。

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（例外スロー） |
| 優先度 | 高（暗号処理エラーは即座に処理中断を要求） |
| リトライ | 無（例外通知自体のリトライは不要、上位層で処理のリトライを判断） |

### 送信先決定ロジック

例外のスローは呼び出しスタックに沿って伝播する。送信先は以下のロジックで決定される：

1. 直近の呼び出し元にエラーハンドラ（On Error GoTo）が存在する場合、そのハンドラに到達
2. 呼び出し元にハンドラがない場合、さらに上位の呼び出し元へ伝播
3. 最終的にハンドラがない場合、VB6ランタイムのデフォルトエラーハンドラが処理

## 通知テンプレート

### 例外通知の場合

| 項目 | 内容 |
|-----|------|
| 例外クラス名 | CryptographicException |
| 名前空間 | System.Security.Cryptography |
| 継承階層 | Exception → SystemException → CryptographicException |

### メッセージテンプレート

```
{エラー詳細メッセージ}

例：
"Invalid padding."
"Could not decrypt data. {Windows API エラーメッセージ}"
"Encryption failed: {Windows API エラーメッセージ}"
"Length of data to be encrypted is incorrect."
"Output Feedback (OFB) mode is not supported."
"Key cannot be weak."
"Key cannot be semi-weak."
"Cannot change key after hash has started."
"The Cryptography Service Provider (CSP) does not support the specified algorithm."
"Invalid key length."
"Invalid hash length."
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| - | - | - | 例外通知には添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Message | エラーメッセージ | 呼び出し元から渡されるパラメータ、またはGetMessage(Err.LastDllError) | Yes |
| HResult | HRESULT値 | 固定値：CORSEC_E_CRYPTO | Yes |
| ErrorNumber | VBエラー番号 | 固定値：vbInvalidProcedureCall (5) | Yes |
| Source | エラー発生元 | ExceptionBase.Source（App情報から自動設定） | No |
| InnerException | 内部例外 | 呼び出し元から渡されるパラメータ | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 暗号API操作 | CryptoAPI関数呼び出し失敗 | CryptEncrypt/CryptDecrypt戻り値がBOOL_FALSE | Windows CryptoAPIの暗号化・復号化失敗 |
| 暗号API操作 | キーインポート失敗 | CryptImportKey戻り値がBOOL_FALSE | 暗号キーのインポート失敗 |
| パディング検証 | パディングパターン不正 | パディングバイト値がブロックサイズを超過、またはパターン不一致 | 復号化時のパディング検証エラー |
| キー検証 | キー長不正 | キー配列長が規定値と不一致 | DES/TripleDES等のキー長チェック |
| キー検証 | 弱いキー検出 | DES.IsWeakKeyまたはDES.IsSemiWeakKeyがTrue | セキュリティ上脆弱なキーの使用拒否 |
| モード検証 | 非対応暗号モード | CipherMode.OFB指定時 | OFBモードはCryptoAPIでサポートされない |
| ハッシュ操作 | ハッシュ計算失敗 | CryptHashData/CryptGetHashParam戻り値がBOOL_FALSE | ハッシュアルゴリズムの処理エラー |
| 状態検証 | 不正な状態変更 | ハッシュ開始後のキー変更 | HMAC/MACのキー変更制約 |
| CSP操作 | プロバイダー取得失敗 | CryptAcquireContext失敗 | 暗号サービスプロバイダーのコンテキスト取得エラー |
| XML操作 | 不正なXML形式 | RSA/DSAパラメータのXML読み込み失敗 | 暗号パラメータのXML形式エラー |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常終了時 | 暗号操作が正常に完了した場合は例外をスローしない |
| NTE_BAD_KEYSET後のリトライ成功時 | コンテキスト取得失敗がキーセット未作成の場合、CRYPT_NEWKEYSETフラグで再試行し成功すれば例外なし |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[暗号操作開始] --> B[Windows CryptoAPI呼び出し]
    B --> C{API戻り値チェック}
    C -->|成功| D[正常終了]
    C -->|失敗| E[エラー情報取得]
    E --> F[Err.LastDllErrorからメッセージ取得]
    F --> G[Cor.NewCryptographicException呼び出し]
    G --> H[新しい例外インスタンス生成]
    H --> I[Init: Message, InnerException設定]
    I --> J[Throw実行]
    J --> K[呼び出しスタック遡上]
    K --> L{エラーハンドラ存在?}
    L -->|Yes| M[ハンドラで例外処理]
    L -->|No| N[上位へ伝播継続]
    M --> O[終了]
    N --> K
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| - | - | 本通知はデータベース操作を行わない |

### テーブル別参照項目詳細

該当なし（本例外はメモリ上の処理のみ）

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| - | - | 本通知はデータベース操作を行わない |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| - | - | - | ログ記録は呼び出し元の責任（例外自体はログを出力しない） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 暗号化失敗 | CryptEncrypt API失敗 | キー、モード、パディングの設定を確認。データ長がブロックサイズの倍数か確認 |
| 復号化失敗 | CryptDecrypt API失敗 | 暗号化時と同じキー・IV・モードを使用しているか確認 |
| パディングエラー | 不正なパディング検出 | 暗号化・復号化で同じPaddingModeを使用しているか確認 |
| キー長エラー | キーサイズ不正 | アルゴリズムが要求するキーサイズに合わせる |
| 弱いキー | DES/TripleDESの弱いキー | キーを再生成（ランダムに生成すれば通常は問題なし） |
| CSPエラー | プロバイダー取得失敗 | システムの暗号プロバイダーがインストールされているか確認 |
| OFBモードエラー | 非対応モード指定 | CBC、CFB、ECBなど対応モードを使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 例外通知自体はリトライ不可（上位層で判断） |
| リトライ間隔 | - |
| リトライ対象エラー | CSP初期化失敗時のCRYPT_NEWKEYSETフラグ付き再試行のみ内部でリトライ |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（例外発生頻度に応じてスロー） |
| 1日あたり上限 | なし |

### 配信時間帯

例外は発生時に即座にスローされる（時間帯制限なし）

## セキュリティ考慮事項

- **機密情報の非露出**：例外メッセージに暗号キー、パスワード、平文データを含めてはならない
- **エラー情報の抽象化**：Windows CryptoAPI由来のエラーメッセージは、アルゴリズムの脆弱性を推測されないよう必要に応じて抽象化を検討
- **ログ出力時の配慮**：例外をログ出力する際、InnerExceptionチェーンに機密情報が含まれていないか確認
- **エラーメッセージの一貫性**：サイドチャネル攻撃を防ぐため、成功・失敗時の処理時間が大きく異ならないよう注意
- **監査記録**：暗号処理失敗はセキュリティインシデントの可能性があるため、監査ログへの記録を推奨

## 備考

- .NET FrameworkのSystem.Security.Cryptography.CryptographicExceptionクラスとの互換性を意図した設計
- HResultとしてCORSEC_E_CRYPTO（セキュリティ関連の特別なHRESULT）を使用
- ExceptionBaseクラスに例外の共通機能（Message、InnerException、Data等の管理）を委譲
- Persistable属性によりPropertyBagを使用したシリアライズ・デシリアライズが可能
- 本例外は約15のソースファイルで使用され、39箇所以上でThrow文が記述されている

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、例外クラスの継承階層とインターフェース実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CryptographicException.cls | `Source/CorLib/System.Security.Cryptography/CryptographicException.cls` | 41-44行目：Implements宣言でIObject、Exception、SystemExceptionを実装。50行目：mBaseでExceptionBaseに処理委譲 |
| 1-2 | ExceptionBase.cls | `Source/CorLib/System/ExceptionBase.cls` | 例外の共通機能（Message、InnerException、Data、ToString等）を提供するヘルパークラス |

**読解のコツ**: CryptographicExceptionはIObject、Exception、SystemExceptionの3つのインターフェースを実装している。実際の処理はExceptionBaseに委譲されており、94-96行目のHResultプロパティで返却されるCORSEC_E_CRYPTOが暗号関連例外の特徴である。

#### Step 2: エントリーポイントを理解する

例外オブジェクトの生成起点となるコンストラクタ関数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Constructors.cls | `Source/CorLib/System/Constructors.cls` | 1161-1163行目：NewCryptographicException関数が例外生成の起点 |

**主要処理フロー**:
1. **1161行目**: 関数定義。Message（必須）、InnerException（任意）を受け取る
2. **1162行目**: New CryptographicExceptionでインスタンス生成
3. **1163行目**: Initメソッドを呼び出し、各プロパティを初期化

#### Step 3: 例外をスローするクラス群を理解する

暗号操作クラスがどのような条件でCryptographicExceptionをスローするかを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CryptoAPI.cls | `Source/CorLib/System.Security.Cryptography/CryptoAPI.cls` | 285-287行目：CryptoErrorヘルパー関数。Windows API失敗時にErr.LastDllErrorからメッセージ取得してスロー |
| 3-2 | CryptoAPITransform.cls | `Source/CorLib/System.Security.Cryptography/CryptoAPITransform.cls` | 206-207行目：OFBモード非対応エラー、259行目：データ長エラー、281行目：暗号化失敗、304行目：暗号化失敗、349行目：復号化失敗、357行目：データ長エラー、399行目：復号化失敗 |
| 3-3 | CryptoHelper.cls | `Source/CorLib/System.Security.Cryptography/CryptoHelper.cls` | 181行目、205行目：パディング検証エラー |
| 3-4 | ErrorStatic.cls | `Source/CorLib/System/ErrorStatic.cls` | 95-105行目：Cryptographicヘルパー関数。リソースキーまたはLastDllErrorからメッセージ生成 |

**主要処理フロー**:
- **CryptoAPI.cls 285-287行目**: CryptoError関数でGetMessage(Err.LastDllError)を使用してWindows APIエラーを例外メッセージに変換
- **CryptoAPITransform.cls 280-281行目**: CryptEncrypt失敗時に「Encryption failed: {エラーメッセージ}」形式でスロー
- **CryptoHelper.cls 180-181行目**: パディング長がInputBlockSizeを超過した場合「Invalid padding.」でスロー

#### Step 4: 使用例（暗号サービスプロバイダー）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | RSACryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/RSACryptoServiceProvider.cls` | 612-613行目：キー取得失敗、632行目：アルゴリズム非対応、635行目：キー生成失敗、670行目：ハッシュ長エラー、674行目：ハッシュ作成失敗、678行目：ハッシュパラメータ設定失敗 |
| 4-2 | DESCryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/DESCryptoServiceProvider.cls` | 469行目：弱いキーエラー、471行目：セミ弱いキーエラー |
| 4-3 | TripleDESCryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/TripleDESCryptoServiceProvider.cls` | 382行目：弱いキーエラー |

### プログラム呼び出し階層図

```
暗号操作（例：RSACryptoServiceProvider.SignHash）
    │
    ├─ Windows CryptoAPI呼び出し（CryptSignHash等）
    │      │
    │      └─ 失敗時：Err.LastDllError設定
    │
    └─ 失敗判定
           │
           └─ Cor.NewCryptographicException
                  │
                  ├─ New CryptographicException
                  │      └─ Class_InitProperties
                  │             └─ Cor.NewExceptionBase
                  │
                  └─ CryptographicException.Init
                         ├─ mBase.Message = Message
                         └─ Set mBase.InnerException = InnerException

CryptoAPITransform.EncryptFinalBlock
    │
    ├─ パディング処理（CryptoHelper.PadBlock）
    │
    ├─ CryptEncrypt API呼び出し
    │      │
    │      └─ 失敗時：Throw Cor.NewCryptographicException("Encryption failed: " & GetMessage)
    │
    └─ 正常終了

CryptoHelper.DepadBlock
    │
    ├─ パディング長チェック（> InputBlockSize）
    │      └─ 失敗：Throw Cor.NewCryptographicException("Invalid padding.")
    │
    ├─ パターン検証（PKCS7/ANSIX923）
    │      └─ 失敗：Throw Cor.NewCryptographicException("Invalid padding.")
    │
    └─ 正常終了
```

### データフロー図

```
[入力]                           [処理]                                 [出力]

暗号操作パラメータ ───────▶ Windows CryptoAPI呼び出し ───┐
（キー、データ、IV等）                                     │
                                                          ▼
                                              ┌─────────────────────┐
                                              │   API戻り値チェック   │
                                              └─────────────────────┘
                                                          │
                              ┌────────────────┬──────────┴──────────┐
                              ▼                                      ▼
                    [失敗: BOOL_FALSE]                        [成功: 非BOOL_FALSE]
                              │                                      │
                              ▼                                      ▼
            ┌─────────────────────────────┐                  処理済みデータ
            │ Err.LastDllError取得         │
            │ GetMessage()でメッセージ生成  │
            └─────────────────────────────┘
                              │
                              ▼
            ┌─────────────────────────────┐
            │ Cor.NewCryptographicException│
            │   - Message設定              │
            │   - InnerException設定       │
            └─────────────────────────────┘
                              │
                              ▼
            ┌─────────────────────────────┐
            │        Throw 実行            │
            │   例外が呼び出しスタックを    │
            │   遡上してハンドラへ到達     │
            └─────────────────────────────┘
                              │
                              ▼
            ┌─────────────────────────────┐
            │ 例外オブジェクト（受信者へ）   │
            │   - Message                  │
            │   - HResult (CORSEC_E_CRYPTO)│
            │   - ErrorNumber (5)          │
            │   - Source                   │
            │   - InnerException           │
            │   - Data                     │
            └─────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CryptographicException.cls | `Source/CorLib/System.Security.Cryptography/CryptographicException.cls` | ソース | 主要な例外クラス実装（全361行） |
| ExceptionBase.cls | `Source/CorLib/System/ExceptionBase.cls` | ソース | 例外共通機能のヘルパークラス |
| Constructors.cls | `Source/CorLib/System/Constructors.cls` | ソース | NewCryptographicException関数（1161-1163行目） |
| ErrorStatic.cls | `Source/CorLib/System/ErrorStatic.cls` | ソース | Cryptographicヘルパー関数（95-105行目） |
| CryptoAPI.cls | `Source/CorLib/System.Security.Cryptography/CryptoAPI.cls` | ソース | 暗号APIラッパー。CryptoError関数（285-287行目） |
| CryptoAPITransform.cls | `Source/CorLib/System.Security.Cryptography/CryptoAPITransform.cls` | ソース | 暗号変換クラス。7箇所でスロー |
| CryptoAPIHash.cls | `Source/CorLib/System.Security.Cryptography/CryptoAPIHash.cls` | ソース | ハッシュクラス。3箇所でスロー |
| CryptoHelper.cls | `Source/CorLib/System.Security.Cryptography/CryptoHelper.cls` | ソース | パディング処理。2箇所でスロー |
| RSACryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/RSACryptoServiceProvider.cls` | ソース | RSA暗号クラス。6箇所以上でスロー |
| DSACryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/DSACryptoServiceProvider.cls` | ソース | DSA署名クラス。1箇所でスロー |
| DESCryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/DESCryptoServiceProvider.cls` | ソース | DES暗号クラス。2箇所でスロー |
| TripleDESCryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/TripleDESCryptoServiceProvider.cls` | ソース | TripleDES暗号クラス。1箇所でスロー |
| DESStatic.cls | `Source/CorLib/System.Security.Cryptography/DESStatic.cls` | ソース | DES静的ヘルパー。2箇所でスロー |
| TripleDESStatic.cls | `Source/CorLib/System.Security.Cryptography/TripleDESStatic.cls` | ソース | TripleDES静的ヘルパー。1箇所でスロー |
| RNGCryptoServiceProvider.cls | `Source/CorLib/System.Security.Cryptography/RNGCryptoServiceProvider.cls` | ソース | 乱数生成クラス。1箇所でスロー |
| RijndaelManagedTransform.cls | `Source/CorLib/System.Security.Cryptography/RijndaelManagedTransform.cls` | ソース | Rijndael変換クラス。3箇所でスロー |
| HMACBase.cls | `Source/CorLib/System.Security.Cryptography/HMACBase.cls` | ソース | HMACベースクラス。1箇所でスロー |
| MACTripleDES.cls | `Source/CorLib/System.Security.Cryptography/MACTripleDES.cls` | ソース | MACクラス。1箇所でスロー |
| RSAParameters.cls | `Source/CorLib/System.Security.Cryptography/RSAParameters.cls` | ソース | RSAパラメータ。3箇所でスロー |
| DSAParameters.cls | `Source/CorLib/System.Security.Cryptography/DSAParameters.cls` | ソース | DSAパラメータ。2箇所でスロー |
| CspKeyContainerInfo.cls | `Source/CorLib/System.Security.Cryptography/CspKeyContainerInfo.cls` | ソース | CSPキーコンテナ情報。1箇所でスロー |
