Developer-Dashboard
view release on metacpan or search on metacpan
t/651-crypto-pbkdf2-ffi.t view on Meta::CPAN
{
package Local::PBKDF2FakeFFI;
our ( $LIBRARY, $CONSTRUCTOR_ARGS, $SHA256_RESULT, $PBKDF2_RESULT, $BUFFER_MODE, $BUFFER_CALLS );
sub function {
my ( $self, $symbol ) = @_;
return bless { symbol => $symbol }, 'Local::PBKDF2FakeFFIFunction';
}
}
{
package Local::PBKDF2FakeFFIFunction;
sub call {
my ( $self, @args ) = @_;
return $Local::PBKDF2FakeFFI::SHA256_RESULT if $self->{symbol} eq 'EVP_sha256';
my ( $password, $password_size, $salt, $salt_size, $iterations, $sha256, $output_size, $output ) = @args;
return 0 if $Local::PBKDF2FakeFFI::PBKDF2_RESULT != 1;
my $u = Digest::SHA::hmac_sha256( ${$salt} . pack( 'N', 1 ), ${$password} );
my $derived = $u;
for my $round ( 2 .. $iterations ) {
$u = Digest::SHA::hmac_sha256( $u, ${$password} );
$derived ^= $u;
}
${$output} = $derived;
return 1;
}
}
done_testing;
sub _require_test_module {
# _require_test_module($module)
# Loads an optional module used by native-backend fixtures and distinguishes
# that module's absence from an initialization error inside an installed module.
# Input: fully qualified module name.
# Output: true when loaded, false when its own module file is absent.
my ($module) = @_;
( my $file = $module ) =~ s{::}{/}g;
$file .= '.pm';
my $loaded = eval { require $file; 1 };
return 1 if $loaded;
my $error = $@;
return 0 if $error =~ /\ACan't locate \Q$file\E in \@INC\b/;
die $error;
}
__END__
=head1 NAME
t/651-crypto-pbkdf2-ffi.t - Verify native PBKDF2 interoperability
=head1 PURPOSE
This test verifies the optional OpenSSL FFI implementation of
PBKDF2-HMAC-SHA256 against the byte-for-byte behavior currently used by helper
account authentication.
=head1 WHY IT EXISTS
The FFI path collapses hundreds of thousands of Perl-to-XS HMAC calls into one
native call. A digest mismatch would invalidate existing helper credentials,
so the exact digest, iteration count, and Perl byte-string behavior are
security-sensitive compatibility requirements. The suite also supplies a
deterministic fake FFI boundary so backend setup, buffer validation, digest
parity, and explicit native errors are exercised even when optional FFI modules
or system libcrypto are absent from the test environment.
=head1 WHEN TO USE
Run this test when changing the FFI adapter, password derivation, library
discovery, or the supported native fallback behavior.
=head1 HOW TO USE
Run C<prove -lv t/651-crypto-pbkdf2-ffi.t> from a configured Developer
Dashboard checkout. Native integration checks skip when an optional FFI module
or compatible OpenSSL library is unavailable; deterministic mocked-native
checks still exercise successful setup, digest parity, buffer bounds, and
native failure handling. The test also hides each optional FFI module in turn
to verify that module absence selects the Perl fallback without masking
unrelated load failures.
It launches a fresh Perl interpreter with the optional FFI library path hidden
to verify that loading this adapter itself does not require those optional
modules, and checks that failures raised by installed modules remain visible.
=head1 WHAT USES IT
The distribution test suite uses this file to guard the implementation called
by C<Developer::Dashboard::Auth> for helper-user password creation and
verification.
=head1 EXAMPLES
Example 1:
prove -lv t/651-crypto-pbkdf2-ffi.t
Run the isolated digest-parity, byte-semantics, and missing-library/module
fallback checks.
Example 2:
d2 docker compose --project-name dd-problem48-test run --rm dev prove -lv t/651-crypto-pbkdf2-ffi.t
Run the same test in an isolated Docker test project.
Example 3:
PERL5OPT='-MDevel::Cover=-db,cover_db' prove -l t/651-crypto-pbkdf2-ffi.t
Measure the adapter branches while the fake FFI boundary keeps native-path
coverage independent of installed optional modules.
=cut
( run in 0.960 second using v1.01-cache-2.11-cpan-3f962061493 )