c2sp/wycheproof
Community-managed Wycheproof cryptography test vectors and JSON schemas. Validate crypto library implementations against known attacks and spec edge cases across many algorithms (AES-GCM, ECDSA, RSA, HKDF, ChaCha20-Poly1305, Kyber, Dilithium, more).
Install the Package Add the package via Composer:
composer require c2sp/wycheproof
Or manually clone the repository into your project's vendor directory.
Locate Test Vectors
The package provides JSON test vectors in the testvectors_v1/ directory. Key files include:
aes_gcm_test.json (for AES-GCM)ecdsa_secp256r1_sha256_test.json (for ECDSA)rsa_2048_oaep_sha256_test.json (for RSA-OAEP)First Use Case: Validate AES-GCM
Load and parse a test vector file (e.g., aes_gcm_test.json) and validate your encryption/decryption logic:
use Wycheproof\TestVectorLoader;
$loader = new TestVectorLoader();
$testVectors = $loader->load('aes_gcm_test.json');
foreach ($testVectors as $test) {
if ($test->result === 'valid') {
// Encrypt/decrypt using your library and compare outputs
$expectedCiphertext = $test->ciphertext;
$actualCiphertext = encrypt($test->key, $test->plaintext, $test->nonce, $test->aad);
assert($actualCiphertext === $expectedCiphertext, "Test failed for valid case");
}
}
Use Wycheproof to validate cryptographic operations in Laravel's service layer:
class CryptoService {
protected $testVectors;
public function __construct() {
$this->testVectors = (new TestVectorLoader())->load('aes_gcm_test.json');
}
public function validateAesGcm() {
foreach ($this->testVectors as $test) {
if ($test->result === 'invalid') {
// Simulate a malicious input
$result = decrypt($test->key, $test->ciphertext, $test->nonce, $test->aad);
assert($result === false, "Invalid ciphertext should fail decryption");
}
}
}
}
Run Wycheproof tests in GitHub Actions or Laravel Forge:
# .github/workflows/wycheproof.yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install
- run: php artisan wycheproof:run --suite=aes_gcm --suite=ecdsa
Add a custom Artisan command (wycheproof:run) to orchestrate tests.
Generate PHP test cases from JSON schemas for PHPUnit:
use Wycheproof\SchemaGenerator;
$generator = new SchemaGenerator();
$testCases = $generator->generateFromSchema('aead_test_schema.json');
foreach ($testCases as $case) {
$this->assertEquals($case['expected'], encrypt($case['input']));
}
$ecdsaTests = $loader->load('ecdsa_secp256r1_sha256_test.json');
foreach ($ecdsaTests as $test) {
if ($test->result === 'valid') {
$signature = sign($test->privateKey, $test->message);
$this->assertTrue(verify($test->publicKey, $test->message, $signature));
}
}
$rsaTests = $loader->load('rsa_2048_oaep_sha256_test.json');
foreach ($rsaTests as $test) {
if ($test->result === 'invalid') {
$this->assertFalse(decrypt($test->publicKey, $test->ciphertext));
}
}
Use wycheproof's schemas to validate test vector files before processing:
use Wycheproof\SchemaValidator;
$validator = new SchemaValidator();
$isValid = $validator->validate('aes_gcm_test.json', 'aead_test_schema.json');
if (!$isValid) {
throw new \RuntimeException("Invalid test vector format");
}
Schema Mismatches
pbkdf2_hmacsha*_test.json) lack schemas. Handle missing schemas gracefully:
try {
$validator->validate('pbkdf2_hmacsha256_test.json', 'pbkdf2_schema.json');
} catch (\InvalidArgumentException $e) {
// Fallback to manual parsing or skip
}
Result Interpretation
if ($test->result === 'acceptable') {
$this->markTestSkipped("Acceptable case: {$test->label}");
}
Performance Overhead
# Cache test vectors to avoid re-downloading
composer require symfony/cache
Key/Nonce Handling
if (hash_equals($test->nonce, str_repeat("\x00", 12))) {
$this->assertFalse(decrypt($test->key, $test->ciphertext));
}
Deterministic AEAD (SIV)
DaeadTest (e.g., aes_siv_cmac_test.json), the tag is part of the ciphertext. Handle parsing carefully:
$ciphertextWithTag = $test->ciphertext;
$tagLength = 16; // Example for AES-SIV
$actualCiphertext = substr($ciphertextWithTag, 0, -$tagLength);
$actualTag = substr($ciphertextWithTag, -$tagLength);
if ($actual !== $expected) {
\Log::error("Wycheproof test failed", [
'algorithm' => $test->algorithm,
'input' => $test->input,
'expected' => $expected,
'actual' => $actual,
]);
}
json_schema_validator:
Install the package to validate schemas programmatically:
composer require zendframework/zend-json-schema
use Zend\JsonSchema\Validator;
$validator = new Validator();
$result = $validator->validate($testVector, $schema);
Custom Test Loaders
Extend TestVectorLoader to support remote URLs or database-backed vectors:
class RemoteTestVectorLoader extends TestVectorLoader {
public function loadFromUrl(string $url): array {
$content = file_get_contents($url);
return json_decode($content, true);
}
}
Parallel Testing
Use Laravel's parallel:tests package to run Wycheproof tests concurrently:
composer require beyondcode/parallel-tests
// In phpunit.xml
<phpunit ...>
<extensions>
<extension class="BeyondCode\ParallelTests\ParallelExtension"/>
</extensions>
</phpunit>
Visual Regression for Crypto For algorithms like ECDSA, visualize public keys to catch invalid curves:
use Wycheproof\Visualizer;
$visualizer = new Visualizer();
$visualizer->plotKey($test->publicKey); // Save as PNG
vendor/c2sp/wycheproof/testvectors_v1/. Override with:
$loader = new TestVectorLoader('/custom/path/to/vectors');
doc/coverage.md for gaps (e.g., aes_ff1).# GitHub Actions
steps:
- name: Cache Wycheproof vectors
uses: actions/cache@v3
with:
path: vendor/c2sp/wycheproof/testvectors_v1
key: wycheproof-v1-${{ hashFiles('composer.lock
How can I help you explore Laravel packages today?