1#!/usr/bin/env perl 2 3## 4## Author......: See docs/credits.txt 5## License.....: MIT 6## 7 8use strict; 9use warnings; 10 11use Crypt::PBKDF2; 12use MIME::Base64 qw (encode_base64 decode_base64); 13 14sub module_constraints { [[0, 256], [-1, -1], [-1, -1], [-1, -1], [-1, -1]] } 15 16sub module_generate_hash 17{ 18 my $word = shift; 19 my $salt = shift; 20 my $iter = shift // 1024; 21 22 if (length $salt == 0) 23 { 24 $salt = random_bytes (16); 25 } 26 27 my $pbkdf2 = Crypt::PBKDF2->new 28 ( 29 hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512), 30 iterations => $iter 31 ); 32 33 my $hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt, $word), ''); 34 my $salt_buf = encode_base64 ($salt, ''); 35 36 # replace + with . 37 $hash_buf =~ s/\+/\./g; 38 $salt_buf =~ s/\+/\./g; 39 40 # remove padding = 41 $hash_buf =~ s/\=+$//; 42 $salt_buf =~ s/\=+$//; 43 44 my $hash = sprintf ("\$pbkdf2-sha512\$%i\$%s\$%s", $iter, $salt_buf, $hash_buf); 45 46 return $hash; 47} 48 49sub module_verify_hash 50{ 51 my $line = shift; 52 53 # check signature 54 return unless (substr ($line, 0, 15) eq '$pbkdf2-sha512$'); 55 56 # get hash 57 my $index1 = index ($line, '$', 15); 58 59 return if $index1 < 1; 60 61 my $index2 = index ($line, '$', $index1 + 1); 62 63 my $iter = substr ($line, 15, $index1 - 15); 64 65 my $salt = substr ($line, $index1 + 1, $index2 - $index1 - 1); 66 67 $index1 = index ($line, ':', $index2 + 1); 68 69 return if $index1 < 1; 70 71 my $word = substr ($line, $index1 + 1); 72 73 return unless defined $salt; 74 return unless defined $iter; 75 return unless defined $word; 76 77 $word = pack_if_HEX_notation ($word); 78 79 # fix salt from 'alternate' to 'ordinary' base64 encoding before 80 $salt =~ s/\./\+/g; 81 $salt .= '=='; 82 83 my $new_hash = module_generate_hash ($word, decode_base64 ($salt), $iter); 84 85 return ($new_hash, $word); 86} 87 881; 89