Files
michaelschiemer/tests/Unit/Framework/Cryptography/DerivedKeyTest.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

270 lines
7.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Cryptography\DerivedKey;
it('creates derived key with valid parameters', function () {
$key = str_repeat('a', 32);
$salt = str_repeat('b', 32);
$derivedKey = new DerivedKey(
key: $key,
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
expect($derivedKey->getKey())->toBe($key);
expect($derivedKey->getSalt())->toBe($salt);
expect($derivedKey->getAlgorithm())->toBe('pbkdf2-sha256');
expect($derivedKey->getIterations())->toBe(100000);
expect($derivedKey->getKeyLength())->toBe(32);
});
it('throws exception for empty key', function () {
expect(fn () => new DerivedKey(
key: '',
salt: str_repeat('b', 32),
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
))->toThrow(InvalidArgumentException::class, 'Key cannot be empty');
});
it('throws exception for empty salt', function () {
expect(fn () => new DerivedKey(
key: str_repeat('a', 32),
salt: '',
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
))->toThrow(InvalidArgumentException::class, 'Salt cannot be empty');
});
it('throws exception for key length mismatch', function () {
expect(fn () => new DerivedKey(
key: str_repeat('a', 16), // 16 bytes
salt: str_repeat('b', 32),
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32 // Claims 32 bytes
))->toThrow(InvalidArgumentException::class, 'Key length does not match specified length');
});
it('provides hex representation', function () {
$key = "\x01\x02\x03\x04";
$salt = "\x05\x06\x07\x08";
$derivedKey = new DerivedKey(
key: $key,
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 4
);
expect($derivedKey->getKeyHex())->toBe('01020304');
expect($derivedKey->getSaltHex())->toBe('05060708');
});
it('provides base64 representation', function () {
$key = 'test-key-data';
$salt = 'test-salt-data';
$derivedKey = new DerivedKey(
key: $key,
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: strlen($key)
);
expect($derivedKey->getKeyBase64())->toBe(base64_encode($key));
expect($derivedKey->getSaltBase64())->toBe(base64_encode($salt));
});
it('checks equality correctly', function () {
$key = str_repeat('a', 32);
$salt = str_repeat('b', 32);
$derivedKey1 = new DerivedKey(
key: $key,
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
$derivedKey2 = new DerivedKey(
key: $key,
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
$derivedKey3 = new DerivedKey(
key: str_repeat('c', 32), // Different key
salt: $salt,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
expect($derivedKey1->equals($derivedKey2))->toBeTrue();
expect($derivedKey1->equals($derivedKey3))->toBeFalse();
});
it('exports to array correctly', function () {
$derivedKey = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'argon2id',
iterations: 4,
keyLength: 32,
memoryCost: 65536,
threads: 3
);
$array = $derivedKey->toArray();
expect($array)->toHaveKey('key');
expect($array)->toHaveKey('salt');
expect($array)->toHaveKey('algorithm');
expect($array)->toHaveKey('iterations');
expect($array)->toHaveKey('key_length');
expect($array)->toHaveKey('memory_cost');
expect($array)->toHaveKey('threads');
expect($array['algorithm'])->toBe('argon2id');
expect($array['memory_cost'])->toBe(65536);
expect($array['threads'])->toBe(3);
});
it('creates from array correctly', function () {
$originalKey = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
$array = $originalKey->toArray();
$restoredKey = DerivedKey::fromArray($array);
expect($restoredKey->equals($originalKey))->toBeTrue();
});
it('creates from hex correctly', function () {
$keyHex = '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20';
$saltHex = 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef';
$derivedKey = DerivedKey::fromHex(
keyHex: $keyHex,
saltHex: $saltHex,
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
expect($derivedKey->getKeyHex())->toBe($keyHex);
expect($derivedKey->getSaltHex())->toBe($saltHex);
});
it('provides summary information', function () {
$derivedKey = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 16),
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
$summary = $derivedKey->getSummary();
expect($summary)->toHaveKey('algorithm');
expect($summary)->toHaveKey('iterations');
expect($summary)->toHaveKey('key_length');
expect($summary)->toHaveKey('salt_length');
expect($summary['salt_length'])->toBe(16);
});
it('identifies algorithm types correctly', function () {
$pbkdf2Key = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'pbkdf2-sha256',
iterations: 100000,
keyLength: 32
);
$argon2Key = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'argon2id',
iterations: 4,
keyLength: 32
);
$scryptKey = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'scrypt',
iterations: 16384,
keyLength: 32
);
expect($pbkdf2Key->isPbkdf2())->toBeTrue();
expect($pbkdf2Key->isArgon2())->toBeFalse();
expect($pbkdf2Key->isScrypt())->toBeFalse();
expect($argon2Key->isArgon2())->toBeTrue();
expect($argon2Key->isPbkdf2())->toBeFalse();
expect($scryptKey->isScrypt())->toBeTrue();
expect($scryptKey->isPbkdf2())->toBeFalse();
});
it('handles scrypt parameters correctly', function () {
$derivedKey = new DerivedKey(
key: str_repeat('a', 32),
salt: str_repeat('b', 32),
algorithm: 'scrypt',
iterations: 16384,
keyLength: 32,
blockSize: 8,
parallelization: 1
);
expect($derivedKey->getBlockSize())->toBe(8);
expect($derivedKey->getParallelization())->toBe(1);
});
it('throws exception for missing required fields in fromArray', function () {
$incompleteData = [
'key' => base64_encode(str_repeat('a', 32)),
'salt' => base64_encode(str_repeat('b', 32)),
'algorithm' => 'pbkdf2-sha256',
// Missing iterations and key_length
];
expect(fn () => DerivedKey::fromArray($incompleteData))
->toThrow(InvalidArgumentException::class, 'Missing required field');
});
it('throws exception for invalid base64 in fromArray', function () {
$invalidData = [
'key' => 'invalid-base64!@#',
'salt' => base64_encode(str_repeat('b', 32)),
'algorithm' => 'pbkdf2-sha256',
'iterations' => 100000,
'key_length' => 32,
];
expect(fn () => DerivedKey::fromArray($invalidData))
->toThrow(InvalidArgumentException::class, 'Failed to decode Base64 data');
});