Crypt-OpenSSL-FASTPBKDF2
view release on metacpan or search on metacpan
FASTPBKDF2.xs view on Meta::CPAN
printf("%s: ", label);
for (size_t i = 0; i < n; i++)
printf("%02x", data[i]);
printf("\n");
}
MODULE = Crypt::OpenSSL::FASTPBKDF2 PACKAGE = Crypt::OpenSSL::FASTPBKDF2
PROTOTYPES: ENABLE
SV *
fastpbkdf2_hmac_interface(pw, salt, iterations, nout, IN_OUT data_buffer = newAV())
SV * pw
SV * salt
uint32_t iterations
STRLEN nout
AV * &data_buffer
PROTOTYPE: $$$$;\@
PREINIT:
STRLEN npw;
STRLEN nsalt;
uint8_t * cpw;
uint8_t * csalt;
uint8_t * hashPtr;
SV * hash = newSVpv("",0);
INIT:
cpw = SvPVbyte(pw, npw);
csalt = SvPVbyte(salt, nsalt);
Newx(hashPtr, nout+1, uint8_t);
sv_usepvn_flags(hash, hashPtr, nout, SV_SMAGIC | SV_HAS_TRAILING_NUL);
C_ARGS:
cpw, npw, csalt, nsalt, iterations, hashPtr, nout
INTERFACE:
fastpbkdf2_hmac_sha1 fastpbkdf2_hmac_sha256 fastpbkdf2_hmac_sha512
POSTCALL:
if(ST(5)) av_push(data_buffer, newSVpvn(hashPtr, nout)); // Append to @data_buffer array, if provided
hashPtr[nout] = '\0'; // NUL-terminated string
RETVAL = hash;
This module requires these other modules and libraries:
DynaLoader
OpenSSL
SYNOPSIS
use Crypt::OpenSSL::FASTPBKDF2 qw/fastpbkdf2_hmac_sha1 fastpbkdf2_hmac_sha256 fastpbkdf2_hmac_sha512/;
# Initialize parameters for password, salt, number of iterations, and desired output length (in bytes)
my ($password, $salt, $num_iterations, $output_len) = ('password', 'salt', 100, 32);
# Initialize buffer array (optional argument)
my @buffer;
# Set hash results into scalar variables
my $hash_sha1 = fastpbkdf2_hmac_sha1($password, $salt, $num_iterations, $output_len, @buffer); #= 0x8595d7aea0e7c952a35af9a838cc6b393449307cfcc7bd340e7e32ee90115650
my $hash_sha256 = fastpbkdf2_hmac_sha256($password, $salt, $num_iterations, $output_len, @buffer); #= 0x07e6997180cf7f12904f04100d405d34888fdf62af6d506a0ecc23b196fe99d8
my $hash_sha512 = fastpbkdf2_hmac_sha512($password, $salt, $num_iterations, $output_len, @buffer); #= 0xfef7276b107040a0a713bcbec9fd3e191cc6153249e245a3e1a22087dbe61606
# Print the contents of the buffer as HEX
print unpack('H*', join('', @buffer)); # "8595d7aea0e7c952a35af9a838cc6b393449307cfcc7bd340e7e32ee9011565007e6997180cf7f12904f04100d405d34888fdf62af6d506a0ecc23b196fe99d8fef7276b107040a0a713bcbec9fd3e191cc6153249e245a3e1a22087dbe61606"
COPYRIGHT AND LICENCE
Copyright (C) 2017 Duane Hutchins - Univeral Printing Company
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.16 or,
lib/Crypt/OpenSSL/FASTPBKDF2.pm view on Meta::CPAN
__END__
=head1 NAME
Crypt::OpenSSL::FASTPBKDF2 - Perl wrapper for PBKDF2 keys derivation function of the OpenSSL library using fastpbkdf2
=head1 SYNOPSIS
use Crypt::OpenSSL::FASTPBKDF2 qw/fastpbkdf2_hmac_sha1 fastpbkdf2_hmac_sha256 fastpbkdf2_hmac_sha512/;
# Initialize parameters for password, salt, number of iterations, and desired output length (in bytes)
my ($password, $salt, $num_iterations, $output_len) = ('password', 'salt', 100, 32);
# Initialize buffer array (optional argument)
my @buffer;
# Set hash results into scalar variables
my $hash_sha1 = fastpbkdf2_hmac_sha1($password, $salt, $num_iterations, $output_len, @buffer); #= 0x8595d7aea0e7c952a35af9a838cc6b393449307cfcc7bd340e7e32ee90115650
my $hash_sha256 = fastpbkdf2_hmac_sha256($password, $salt, $num_iterations, $output_len, @buffer); #= 0x07e6997180cf7f12904f04100d405d34888fdf62af6d506a0ecc23b196fe99d8
my $hash_sha512 = fastpbkdf2_hmac_sha512($password, $salt, $num_iterations, $output_len, @buffer); #= 0xfef7276b107040a0a713bcbec9fd3e191cc6153249e245a3e1a22087dbe61606
# Print the contents of the buffer as HEX
print unpack('H*', join('', @buffer)); # "8595d7aea0e7c952a35af9a838cc6b393449307cfcc7bd340e7e32ee9011565007e6997180cf7f12904f04100d405d34888fdf62af6d506a0ecc23b196fe99d8fef7276b107040a0a713bcbec9fd3e191cc6153249e245a3e1a22087dbe61606"
=head1 DESCRIPTION
PBKDF2 applies a pseudorandom function, such as hash-based message authentication code (HMAC), to the input password or passphrase along with a salt value and repeats the process many times to produce a derived key, which can then be used as a crypto...
fastpbkdf2 is a fast PBKDF2-HMAC-{SHA1,SHA256,SHA512} implementation in C. It uses OpenSSL's hash functions, but out-performs OpenSSL's own PBKDF2 thanks to various optimisations in the inner loop.
Crypt::OpenSSL::FASTPBKDF2 is a set of Perl bindings for fastpbkdf2.
=head1 Static Methods
=head2 fastpbkdf2_hmac_sha1 ($password, $salt, $iterations, $output_len, :@buffer)
Executes PBKDF2 via HMAC_SHA1 to hash C<$password> with C<$salt> repeatedly, C<$iterations> times, to derive and return a hash that is C<$output_len> bytes long.
If the optional C<@buffer> param is provided, the result will also be appended onto the array.
=head2 fastpbkdf2_hmac_sha256 ($password, $salt, $iterations, $output_len, :@buffer)
Same as C<fastpbkdf2_hmac_sha1> but instead uses HMAC_SHA256
=head2 fastpbkdf2_hmac_sha512 ($password, $salt, $iterations, $output_len, :@buffer)
Same as C<fastpbkdf2_hmac_sha1> but instead uses HMAC_SHA512
=head1 SEE ALSO
NIST-PBKDF2 L<http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf>
Joseph Birr-Pixton - fastpbkdf2 L<https://github.com/ctz/fastpbkdf2>
=head1 AUTHOR
src/README.md view on Meta::CPAN
It uses OpenSSL's hash functions, but out-performs OpenSSL's own PBKDF2
thanks to [various optimisations in the inner loop](https://jbp.io/2015/08/11/pbkdf2-performance-matters/#strategies).
[](https://travis-ci.org/ctz/fastpbkdf2)
## Interface
```c
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
```
Please see the header file for details and constraints.
## Performance
These values are wall time, output from the `bench` tool.
### AMD64
Hash | OpenSSL | fastpbkdf2 | (comparison)
---------|-------------|--------------|--------------
SHA1 | 11.84s | 3.07s | x3.86
SHA256 | 16.54s | 7.45s | x2.22
SHA512 | 21.90s | 9.33s | x2.34
2<sup>22</sup> iterations, 1.86GHz Intel Atom N2800, amd64.
### ARM
Hash | OpenSSL | fastpbkdf2 | (comparison)
---------|-------------|--------------|--------------
SHA1 | 30.4s | 4.43s | x6.86
SHA256 | 36.52s | 7.04s | x5.19
SHA512 | 77.44s | 28.1s | x2.76
2<sup>20</sup> iterations, Raspberry Pi - 700MHz ARM11.
## Requirements
* OpenSSL's libcrypto.
* C compiler supporting C99.
## Building and testing
Run 'make test' to build and run tests.
The program `bench` provides a very basic performance comparison between OpenSSL and fastpbkdf2.
src/fastpbkdf2.c view on Meta::CPAN
_final(out, &ctx->inner); \
_update(&ctx->outer, out, _hashsz); \
_final(out, &ctx->outer); \
} \
\
\
/* --- PBKDF2 --- */ \
static inline void PBKDF2_F(_name)(const HMAC_CTX(_name) *startctx, \
uint32_t counter, \
const uint8_t *salt, size_t nsalt, \
uint32_t iterations, \
uint8_t *out) \
{ \
uint8_t countbuf[4]; \
write32_be(counter, countbuf); \
\
/* Prepare loop-invariant padding block. */ \
uint8_t Ublock[_blocksz]; \
md_pad(Ublock, _blocksz, _hashsz, _blocksz + _hashsz); \
\
/* First iteration: \
* U_1 = PRF(P, S || INT_32_BE(i)) \
*/ \
HMAC_CTX(_name) ctx = *startctx; \
HMAC_UPDATE(_name)(&ctx, salt, nsalt); \
HMAC_UPDATE(_name)(&ctx, countbuf, sizeof countbuf); \
HMAC_FINAL(_name)(&ctx, Ublock); \
_ctx result = ctx.outer; \
\
/* Subsequent iterations: \
* U_c = PRF(P, U_{c-1}) \
*/ \
for (uint32_t i = 1; i < iterations; i++) \
{ \
/* Complete inner hash with previous U */ \
_xcpy(&ctx.inner, &startctx->inner); \
_xform(&ctx.inner, Ublock); \
_xtract(&ctx.inner, Ublock); \
/* Complete outer hash with inner output */ \
_xcpy(&ctx.outer, &startctx->outer); \
_xform(&ctx.outer, Ublock); \
_xtract(&ctx.outer, Ublock); \
_xxor(&result, &ctx.outer); \
} \
\
/* Reform result into output buffer. */ \
_xtract(&result, out); \
} \
\
static inline void PBKDF2(_name)(const uint8_t *pw, size_t npw, \
const uint8_t *salt, size_t nsalt, \
uint32_t iterations, \
uint8_t *out, size_t nout) \
{ \
assert(iterations); \
assert(out && nout); \
\
/* Starting point for inner loop. */ \
HMAC_CTX(_name) ctx; \
HMAC_INIT(_name)(&ctx, pw, npw); \
\
/* How many blocks do we need? */ \
uint32_t blocks_needed = (uint32_t)(nout + _hashsz - 1) / _hashsz; \
\
OPENMP_PARALLEL_FOR \
for (uint32_t counter = 1; counter <= blocks_needed; counter++) \
{ \
uint8_t block[_hashsz]; \
PBKDF2_F(_name)(&ctx, counter, salt, nsalt, iterations, block); \
\
size_t offset = (counter - 1) * _hashsz; \
size_t taken = MIN(nout - offset, _hashsz); \
memcpy(out + offset, block, taken); \
} \
}
static inline void sha1_extract(SHA_CTX *restrict ctx, uint8_t *restrict out)
{
write32_be(ctx->h0, out);
src/fastpbkdf2.c view on Meta::CPAN
SHA512_Init,
SHA512_Update,
SHA512_Transform,
SHA512_Final,
sha512_cpy,
sha512_extract,
sha512_xor)
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha1)(pw, npw, salt, nsalt, iterations, out, nout);
}
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha256)(pw, npw, salt, nsalt, iterations, out, nout);
}
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
{
PBKDF2(sha512)(pw, npw, salt, nsalt, iterations, out, nout);
}
src/fastpbkdf2.h view on Meta::CPAN
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Calculates PBKDF2-HMAC-SHA1.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha1(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
/** Calculates PBKDF2-HMAC-SHA256.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
/** Calculates PBKDF2-HMAC-SHA512.
*
* @p npw bytes at @p pw are the password input.
* @p nsalt bytes at @p salt are the salt input.
* @p iterations is the PBKDF2 iteration count and must be non-zero.
* @p nout bytes of output are written to @p out. @p nout must be non-zero.
*
* This function cannot fail; it does not report errors.
*/
void fastpbkdf2_hmac_sha512(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout);
#ifdef __cplusplus
}
#endif
#endif
t/Crypt-OpenSSL-FASTPBKDF2.t view on Meta::CPAN
BEGIN { use_ok('Crypt::OpenSSL::FASTPBKDF2', qw/fastpbkdf2_hmac_sha1 fastpbkdf2_hmac_sha256 fastpbkdf2_hmac_sha512/) };
use constant HMAC_SUBS => {
# sha0 => $subref
sha1 => \&fastpbkdf2_hmac_sha1,
sha256 => \&fastpbkdf2_hmac_sha256,
sha512 => \&fastpbkdf2_hmac_sha512,
};
use constant HMAC_DATA => {
# sha0 => [ [password, salt, iterations, hex_output_expected] ... ]
sha1 => [
['password', 'salt', 1, '0c60c80f961f0e71f3a9b524af6012062fe037a6'],
['password', 'salt', 2, 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'],
['password', 'salt', 4096, '4b007901b765489abead49d926f721d065a429c1'],
# ['password', 'salt', 16777216, 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'],
['passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'],
["pass\x00\x77\x6f\x72\x64", "sa\x00\x6c\x74", 4096, '56fa6aa75548099dcc37d7f03425e0c3'],
],
sha256 => [
['passwd', 'salt', 1, '55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783'],
t/Crypt-OpenSSL-FASTPBKDF2.t view on Meta::CPAN
my $hmac = shift;
my $test_sub = HMAC_SUBS()->{$hmac};
my $test_data = HMAC_DATA()->{$hmac};
subtest "HMAC $hmac"=>sub {
plan tests => 1 + scalar @$test_data;
my @buffer;
# Data Test
foreach my $t (@$test_data) {
my ($pw, $salt, $iterations, $expected) = @$t;
my $out_len = length($expected)/2;
my $output = $test_sub->($pw, $salt, $iterations, $out_len, \@buffer);
is( unpack('H*', $output), $expected, $hmac.' data' );
}
# Buffer Test
my @buf_expected = map { $_->[3] } @$test_data;
my @buf_output = map { unpack('H*', $_) } @buffer;
is_deeply(\@buf_output, \@buf_expected, $hmac.' buffer');
};
};
( run in 0.817 second using v1.01-cache-2.11-cpan-71847e10f99 )