mcpField
W
wycheproof

wycheproof

github.com/trailofbitsテスト・品質7.9k5.2k 回インストール今日更新
リポジトリ

wycheproof について

Wycheproof は、暗号実装の正しさや既知の攻撃への対応を検証するテストベクトル集です。暗号ライブラリの開発者や監査担当者向けに、アルゴリズムやパラメーター別の分類と期待結果を提供します。

主な機能

  1. 01複数のアルゴリズムと曲線のベクトル
  2. 02valid、acceptable、invalid の結果区分
  3. 03パラメーター別のテストグループ
  4. 04JSON 形式のテストベクトル
  5. 05テストハーネスと CI の統合ガイド

活用シーン

  1. 01AES-GCM の暗号化と復号を検証
  2. 02ECDSA の署名エンコーディングを確認
  3. 03ECDH が無効な曲線点を拒否するかテスト
  4. 04CI で暗号実装の回帰を検出

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trailofbits/skills --skill wycheproof

インストール後、Claude Code で/wycheproofを入力して読み込まれたか確認します。

同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg

詳細

Wycheproof

Wycheproof は、暗号実装の正確性を検証し、既知の攻撃に対するテストを行うために設計された、広範なテストベクトル集です。Google が開発した当初から、現在はコミュニティが管理するプロジェクトとなっており、貢献者は特定の暗号構成に対するテストベクトルを追加できます。

背景

主な概念
概念説明
テストベクトル暗号実装の正確性を検証するための入力と出力のペア
テストグループ属性(鍵サイズ、IV サイズ、曲線)を共有するテストベクトルの集まり
結果フラグテストが成功(有効)、失敗(無効)、または許容されるかを示します
エッジケーステスト既知の脆弱性や攻撃パターンを対象としたテスト
重要な理由

暗号実装を正しく実装するのは非常に困難です。小さなバグでも、次のような問題を引き起こす可能性があります。

  • 秘密鍵が漏えいする
  • 署名の偽造が可能になる
  • メッセージが復号される
  • 実装によって同じ入力を受け入れるか拒否するかが異なり、コンセンサスの問題が発生する

Wycheproof は、OpenJDK の SHA1withDSA、Bouncy Castle の ECDHC、npm の elliptic パッケージなど、主要なライブラリの脆弱性を発見してきました。

使用する場面

Wycheproof を使用する場面:

  • 暗号実装(AES-GCM、ECDSA、ECDH、RSA など)をテストする
  • 暗号コードがエッジケースを正しく処理することを検証する
  • 既知の攻撃ベクトルに対する実装の動作を検証する
  • 暗号ライブラリ向けの CI/CD を設定する
  • サードパーティ製の暗号コードの正確性を監査する

代替手段を検討する場面:

  • タイミングサイドチャネルをテストする場合(代わりに定時間テストツールを使用してください)
  • 未知の新たなバグを見つける場合(代わりにファジングを使用してください)
  • 独自または実験的な暗号アルゴリズムをテストする場合(Wycheproof は確立されたアルゴリズムのみを対象としています)

クイックリファレンス

シナリオ推奨される方法備考
AES-GCM の実装aes_gcm_test.json を使用します44 個のテストグループにわたる 316 個のテストベクトル
ECDSA の検証特定の曲線に対応する ecdsa_*_test.json を使用します署名の可鍛性と DER エンコーディングをテストします
ECDH 鍵交換ecdh_*_test.json を使用します不正な曲線を利用した攻撃をテストします
RSA 署名rsa_*_test.json を使用しますパディングオラクル攻撃をテストします
ChaCha20-Poly1305chacha20_poly1305_test.json を使用しますAEAD の実装をテストします

テストのワークフロー

Phase 1: Setup                 Phase 2: Parse Test Vectors
┌─────────────────┐          ┌─────────────────┐
│ Add Wycheproof  │    →     │ Load JSON file  │
│ as submodule    │          │ Filter by params│
└─────────────────┘          └─────────────────┘
         ↓                            ↓
Phase 4: CI Integration        Phase 3: Write Harness
┌─────────────────┐          ┌─────────────────┐
│ Auto-update     │    ←     │ Test valid &    │
│ test vectors    │          │ invalid cases   │
└─────────────────┘          └─────────────────┘

リポジトリの構成

Wycheproof リポジトリは、次のように構成されています。

┣ 📜 README.md       : Project overview
┣ 📂 doc             : Documentation
┣ 📂 java            : Java JCE interface testing harness
┣ 📂 javascript      : JavaScript testing harness
┣ 📂 schemas         : Test vector schemas
┣ 📂 testvectors     : Test vectors
┗ 📂 testvectors_v1  : Updated test vectors (more detailed)

主要なフォルダーは testvectors と testvectors_v1 です。どちらにも類似したファイルが含まれていますが、testvectors_v1 にはより詳細な情報が含まれているため、新しい統合にはこちらを推奨します。

サポート対象のアルゴリズム

Wycheproof は、幅広い暗号アルゴリズムのテストベクトルを提供しています。

カテゴリアルゴリズム
共通鍵暗号AES-GCM、AES-EAX、ChaCha20-Poly1305
署名ECDSA、EdDSA、RSA-PSS、RSA-PKCS1
鍵交換ECDH、X25519、X448
ハッシュHMAC、HKDF
曲線secp256k1、secp256r1、secp384r1、secp521r1、ed25519、ed448

テストファイルの構成

各 JSON テストファイルは、特定の暗号構成をテストします。すべてのテストファイルに共通の属性があります。

"algorithm"         : The name of the algorithm tested
"schema"            : The JSON schema (found in schemas folder)
"generatorVersion"  : The version number
"numberOfTests"     : The total number of test vectors in this file
"header"            : Detailed description of test vectors
"notes"             : In-depth explanation of flags in test vectors
"testGroups"        : Array of one or multiple test groups
テストグループ

テストグループは、次のような共通属性に基づいてテストをグループ化します。

  • 鍵サイズ
  • IV サイズ
  • 公開鍵
  • 曲線

この分類を利用すると、テスト対象の構成に関連する特定の条件を満たすテストを抽出できます。

テストベクトルの属性
共通属性

すべてのテストベクトルには、次の4つの共通フィールドがあります。

  • tcId:ファイル内でテストベクトルを一意に識別するID
  • comment:テストケースに関する追加情報
  • flags:特定のテストケースの種類や潜在的な危険性に関する説明(notes フィールドで参照されます)
  • result:テストの期待される結果

result フィールドには、次の3つの値を指定できます。

結果意味
validテストケースは成功するはずです
acceptableテストケースは成功しても問題ありませんが、理想的ではない属性が含まれています
invalidテストケースは失敗するはずです
固有属性

固有属性は、テスト対象のアルゴリズムによって異なります。

アルゴリズム固有属性
AES-GCMkey、iv、aad、msg、ct、tag
ECDH secp256k1public、private、shared
ECDSAmsg、sig、result
EdDSAmsg、sig、pk

実装ガイド

フェーズ1:Wycheproofをプロジェクトに追加する

オプション1:Gitサブモジュール(推奨)

WycheproofをGitサブモジュールとして追加すると、自動更新が可能になります。

git submodule add https://github.com/C2SP/wycheproof.git

オプション2:特定のテストベクトルを取得する

サブモジュールを利用できない場合は、特定のJSONファイルを取得します。

#!/bin/bash

TMP_WYCHEPROOF_FOLDER=".wycheproof/"
TEST_VECTORS=('aes_gcm_test.json' 'aes_eax_test.json')
BASE_URL="https://raw.githubusercontent.com/C2SP/wycheproof/master/testvectors_v1/"

# Create wycheproof folder
mkdir -p $TMP_WYCHEPROOF_FOLDER

# Request all test vector files if they don't exist
for i in "${TEST_VECTORS[@]}"; do
  if [ ! -f "${TMP_WYCHEPROOF_FOLDER}${i}" ]; then
    curl -o "${TMP_WYCHEPROOF_FOLDER}${i}" "${BASE_URL}${i}"
    if [ $? -ne 0 ]; then
      echo "Failed to download ${i}"
      exit 1
    fi
  fi
done
フェーズ2:テストベクトルを解析する

使用するアルゴリズムのテストファイルを特定し、JSONを解析します。

Pythonの例:

import json

def load_wycheproof_test_vectors(path: str):
    testVectors = []
    try:
        with open(path, "r") as f:
            wycheproof_json = json.loads(f.read())
    except FileNotFoundError:
        print(f"No Wycheproof file found at: {path}")
        return testVectors

    # Attributes that need hex-to-bytes conversion
    convert_attr = {"key", "aad", "iv", "msg", "ct", "tag"}

    for testGroup in wycheproof_json["testGroups"]:
        # Filter test groups based on implementation constraints
        if testGroup["ivSize"] < 64 or testGroup["ivSize"] > 1024:
            continue

        for tv in testGroup["tests"]:
            # Convert hex strings to bytes
            for attr in convert_attr:
                if attr in tv:
                    tv[attr] = bytes.fromhex(tv[attr])
            testVectors.append(tv)

    return testVectors

JavaScriptの例:

const fs = require('fs').promises;

async function loadWycheproofTestVectors(path) {
  const tests = [];

  try {
    const fileContent = await fs.readFile(path);
    const data = JSON.parse(fileContent.toString());

    data.testGroups.forEach(testGroup => {
      testGroup.tests.forEach(test => {
        // Add shared test group properties to each test
        test['pk'] = testGroup.publicKey.pk;
        tests.push(test);
      });
    });
  } catch (err) {
    console.error('Error reading or parsing file:', err);
    throw err;
  }

  return tests;
}
フェーズ3:テストハーネスを作成する

有効なテストケースと無効なテストケースの両方を処理するテスト関数を作成します。

Python/pytestの例:

import pytest
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

tvs = load_wycheproof_test_vectors("wycheproof/testvectors_v1/aes_gcm_test.json")

@pytest.mark.parametrize("tv", tvs, ids=[str(tv['tcId']) for tv in tvs])
def test_encryption(tv):
    try:
        aesgcm = AESGCM(tv['key'])
        ct = aesgcm.encrypt(tv['iv'], tv['msg'], tv['aad'])
    except ValueError as e:
        # Implementation raised error - verify test was expected to fail
        assert tv['result'] != 'valid', tv['comment']
        return

    if tv['result'] == 'valid':
        assert ct[:-16] == tv['ct'], f"Ciphertext mismatch: {tv['comment']}"
        assert ct[-16:] == tv['tag'], f"Tag mismatch: {tv['comment']}"
    elif tv['result'] == 'invalid' or tv['result'] == 'acceptable':
        assert ct[:-16] != tv['ct'] or ct[-16:] != tv['tag']

@pytest.mark.parametrize("tv", tvs, ids=[str(tv['tcId']) for tv in tvs])
def test_decryption(tv):
    try:
        aesgcm = AESGCM(tv['key'])
        decrypted_msg = aesgcm.decrypt(tv['iv'], tv['ct'] + tv['tag'], tv['aad'])
    except ValueError:
        assert tv['result'] != 'valid', tv['comment']
        return
    except InvalidTag:
        assert tv['result'] != 'valid', tv['comment']
        assert 'ModifiedTag' in tv['flags'], f"Expected 'ModifiedTag' flag: {tv['comment']}"
        return

    assert tv['result'] == 'valid', f"No invalid test case should pass: {tv['comment']}"
    assert decrypted_msg == tv['msg'], f"Decryption mismatch: {tv['comment']}"

JavaScript/Mochaの例:

const assert = require('assert');

function testFactory(tcId, tests) {
  it(`[${tcId + 1}] ${tests[tcId].comment}`, function () {
    const test = tests[tcId];
    const ed25519 = new eddsa('ed25519');
    const key = ed25519.keyFromPublic(toArray(test.pk, 'hex'));

    let sig;
    if (test.result === 'valid') {
      sig = key.verify(test.msg, test.sig);
      assert.equal(sig, true, `[${test.tcId}] ${test.comment}`);
    } else if (test.result === 'invalid') {
      try {
        sig = key.verify(test.msg, test.sig);
      } catch (err) {
        // Point could not be decoded
        sig = false;
      }
      assert.equal(sig, false, `[${test.tcId}] ${test.comment}`);
    }
  });
}

// Generate tests for all test vectors
for (var tcId = 0; tcId < tests.length; tcId++) {
  testFactory(tcId, tests);
}
フェーズ4:CIとの統合

テストベクトルを最新の状態に保つには、次の方法があります。

  1. Gitサブモジュールを使用する:テスト実行前に、CIでサブモジュールを更新します
  2. 最新のテストベクトルを取得する:テスト実行前に取得スクリプトを実行します
  3. 定期更新を設定する:新しいテストベクトルを検出できるよう、毎週または毎月の更新を設定します

検出される一般的な脆弱性

Wycheproofのテストベクトルは、特定の脆弱性パターンを検出するように設計されています。

脆弱性説明影響を受けるアルゴリズムCVEの例
署名の可鍛性同じメッセージに対して複数の有効な署名が存在するECDSA、EdDSACVE-2024-42459
無効なDERエンコーディング正規形ではないDER署名を受け入れるECDSACVE-2024-42460、CVE-2024-42461
無効な曲線を利用した攻撃無効な曲線上の点を使ったECDHECDH多くのライブラリで一般的
パディングオラクルパディング検証時のタイミング情報漏えいRSA-PKCS1OpenSSLで過去に発生した問題
タグの偽造改変された認証タグを受け入れるAES-GCM、ChaCha20-Poly1305各種実装
署名の可鍛性:詳細

問題: 署名エンコーディングを検証しない実装は、同じメッセージに対する複数の有効な署名を受け入れる可能性があります。

例(EdDSA): 署名にゼロを追加または削除する:

Valid signature:   ...6a5c51eb6f946b30d
Invalid signature: ...6a5c51eb6f946b30d0000  (should be rejected)

検出方法:

# Add signature length check
if len(sig) != 128:  # EdDSA signatures must be exactly 64 bytes (128 hex chars)
    return False

影響: 異なる実装が同じ署名を受け入れたり拒否したりすることで、コンセンサスの問題につながる可能性があります。

関連するWycheproofのテスト:

  • EdDSA:tcId 37 - 「署名から0バイトを削除」
  • ECDSA:tcId 06 - 「レガシー:rのASNエンコーディングで先頭の0が欠落」

ケーススタディ:Elliptic npmパッケージ

このケーススタディでは、Wycheproofが人気の高いelliptic npmパッケージ(依存先3000以上、週に数百万回ダウンロード)で3件のCVEを発見した経緯を紹介します。

概要

ellipticライブラリは、JavaScriptで記述された楕円曲線暗号ライブラリで、ECDH、ECDSA、EdDSAをサポートしています。バージョン6.5.6にWycheproofのテストベクトルを適用した結果、複数の脆弱性が明らかになりました。

  • CVE-2024-42459:EdDSA署名の可鍛性(ゼロの追加/削除)
  • CVE-2024-42460:ECDSA DERエンコーディング - 無効なビット配置
  • CVE-2024-42461:ECDSA DERエンコーディング - 長さフィールドの先頭のゼロ
方法論
  1. サポート対象の曲線を特定する:EdDSA では ed25519
  2. テストベクトルを見つける:testvectors_v1/ed25519_test.json
  3. テストベクトルを解析する:JSON を読み込み、テストを抽出します
  4. テストハーネスを作成する:パラメーター化されたテストを作成します
  5. テストを実行する:失敗を特定します
  6. 根本原因を分析する:実装コードを調べます
  7. 修正を提案する:検証チェックを追加します
主な調査結果

EdDSA の問題(CVE-2024-42459):

  • 署名の長さ検証が不足していました
  • 署名の末尾のゼロが許容されていました
  • 修正:if(sig.length !== 128) return false; を追加します

ECDSA の問題 1(CVE-2024-42460):

  • DER エンコードされた r 値と s 値の先頭ビットがゼロであることを確認していませんでした
  • 修正:if ((data[p.place] & 128) !== 0) return false; を追加します

ECDSA の問題 2(CVE-2024-42461):

  • DER の長さフィールドで先頭のゼロが許容されていました
  • 修正:if(buf[p.place] === 0x00) return false; を追加します
影響

これら3つの脆弱性により、単一のメッセージに対して複数の有効な署名が可能になり、実装間でコンセンサスの問題が発生しました。

得られた教訓:

  • Wycheproof は、見つけにくいエンコードのバグを検出します
  • 再利用可能なテストハーネスは大きな効果をもたらします
  • テストベクトルのコメントやフラグは、問題の診断に役立ちます
  • 広く使われているライブラリでも、テストベクトルを体系的に検証するメリットがあります

高度な使い方

ヒントとテクニック
ヒント役立つ理由
パラメーターでテストグループを絞り込む実装の制約に関連するテストベクトルに集中できます
テストベクトルのフラグを使用するテスト対象の脆弱性の具体的なパターンを把握できます
notes フィールドを確認するフラグの意味について詳しい説明を確認できます
暗号化/復号と署名/検証の両方をテストする双方向の正しさを確認できます
CI でテストを実行するリグレッションを検出し、新しいテストベクトルを活用できます
パラメーター化されたテストを使用するtcId とコメントを含む明確な失敗メッセージを取得できます
よくある間違い
間違い問題となる理由正しい方法
有効なケースだけをテストする無効な入力が受け入れられる脆弱性を見逃します有効、無効、許容可能のすべての結果タイプをテストします
「許容可能」な結果を無視する実装に見つけにくいバグがある可能性があります許容可能な結果も、調査すべき警告として扱います
テストグループを絞り込まないサポートしていないパラメーターのテストに時間を浪費します実装に応じて keySize、ivSize などで絞り込みます
テストベクトルを更新しない新たな脆弱性パターンを見逃しますサブモジュールまたはスケジュールされたフェッチを使用します
一方向だけをテストする暗号化/署名は動作しても、復号/検証は失敗する場合があります両方の操作をテストします

関連スキル

ツールスキル
スキルWycheproof テストでの主な用途
pytestパラメーター化されたテストに使う Python テストフレームワーク
mochaテストの生成に使う JavaScript テストフレームワーク
constant-time-testingWycheproof をタイミングサイドチャネルテストで補完します
cryptofuzz追加のバグを見つけるファズベースの暗号テスト
テクニックのスキル
スキル適用する場面
coverage-analysisテストベクトルが暗号実装のすべてのコードパスをカバーしていることを確認します
property-based-testing数学的な性質(暗号化/復号のラウンドトリップなど)をテストします
fuzz-harness-writing暗号パーサー向けのハーネスを作成します(Wycheproof を補完します)
関連するドメインスキル
スキル関連性
crypto-testingWycheproof は、包括的な暗号テスト手法における重要なツールです
fuzzingWycheproof ではカバーされないバグ(新たなエッジケース)をファジングで見つけます

スキルの依存関係マップ

                    ┌─────────────────────┐
                    │    wycheproof       │
                    │   (this skill)      │
                    └──────────┬──────────┘
                               │
           ┌───────────────────┼───────────────────┐
           │                   │                   │
           ▼                   ▼                   ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  pytest/mocha   │ │ constant-time   │ │   cryptofuzz    │
│ (test framework)│ │   testing       │ │   (fuzzing)     │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
         │                   │                   │
         └───────────────────┼───────────────────┘
                             │
                             ▼
              ┌──────────────────────────┐
              │   Technique Skills       │
              │ coverage, harness, PBT   │
              └──────────────────────────┘

リソース

公式リポジトリ

Wycheproof GitHub リポジトリ

公式リポジトリには、以下が含まれています:

  • testvectors/ と testvectors_v1/ にあるすべてのテストベクトル
  • schemas/ にある JSON スキーマ
  • Java と JavaScript のリファレンス実装
  • doc/ にあるドキュメント
実際の活用例

pycryptodome

pycryptodome ライブラリは、Wycheproof のテストベクトルをテストスイートに統合しており、Python の暗号実装におけるベストプラクティスを示しています。

コミュニティリソース
  • C2SP Community - Wycheproof を維持管理する暗号仕様および標準のコミュニティ
  • Wycheproof issues tracker - テストベクトルのバグを報告したり、新しい構成を提案したりできます

まとめ

Wycheproof は、既知の攻撃ベクトルやエッジケースに対して暗号実装を検証するために欠かせないツールです。Wycheproof のテストベクトルをテストワークフローに統合することで、次のことが可能になります。

  1. 微妙なエンコードや検証のバグを発見する
  2. 署名の可鍛性に関する問題を防ぐ
  3. 実装間で一貫した動作を確保する
  4. コミュニティから提供されたテストベクトルを活用する
  5. 既知の暗号脆弱性から保護する

再利用可能なテストハーネスを作成するための投資は、Wycheproof リポジトリに新しいテストベクトルが追加されるたびに継続的な検証を行えるため、大きな成果につながります。

コメント