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 Crypt::AuthEnc::GCM; 13use MIME::Base64 qw (decode_base64 encode_base64); 14 15sub module_constraints { [[0, 256], [32, 32], [-1, -1], [-1, -1], [-1, -1]] } 16 17sub module_generate_hash 18{ 19 my $word = shift; 20 my $salt = shift; 21 my $iv = shift // random_hex_string (24); 22 my $ct = shift; 23 24 my $kdf = Crypt::PBKDF2->new 25 ( 26 hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256), 27 iterations => 4096, 28 output_len => 32 29 ); 30 31 my $salt_bin = pack ("H*", $salt); 32 33 my $key = $kdf->PBKDF2 ($salt_bin, $word); 34 35 my $iv_bin = pack ("H*", $iv); 36 37 my $pt; 38 39 if (defined $ct) 40 { 41 my $ct_bin = pack ("H*", $ct); 42 43 my $data_bin = substr ($ct_bin, 0, -16); 44 my $tag_bin = substr ($ct_bin, -16); 45 46 my $aes = Crypt::AuthEnc::GCM->new ("AES", $key, $iv_bin); 47 48 $pt = $aes->decrypt_add ($data_bin); 49 50 my $result_tag = $aes->decrypt_done ($tag_bin); 51 52 if ($result_tag == 1) 53 { 54 ## correct password 55 } 56 else 57 { 58 $pt = "\xff" x 56; 59 } 60 } 61 else 62 { 63 $pt = "\xff" x 56; 64 } 65 66 my $aes = Crypt::AuthEnc::GCM->new ("AES", $key, $iv_bin); 67 68 my $ct_bin = $aes->encrypt_add ($pt); 69 70 my $tag_bin = $aes->encrypt_done (); 71 72 my $hash = sprintf ('$stellar$%s$%s$%s', encode_base64 ($salt_bin, ""), encode_base64 ($iv_bin, ""), encode_base64 ($ct_bin . $tag_bin, "")); 73 74 return $hash; 75} 76 77sub module_verify_hash 78{ 79 my $line = shift; 80 81 my $idx = index ($line, ':'); 82 83 return unless $idx >= 0; 84 85 my $hash = substr ($line, 0, $idx); 86 my $word = substr ($line, $idx + 1); 87 88 return unless substr ($hash, 0, 9) eq '$stellar$'; 89 90 my (undef, $signature, $salt, $iv, $ct) = split '\$', $hash; 91 92 return unless defined $signature; 93 return unless defined $salt; 94 return unless defined $iv; 95 return unless defined $ct; 96 97 my $salt_bin = decode_base64 ($salt); 98 my $iv_bin = decode_base64 ($iv); 99 my $ct_bin = decode_base64 ($ct); 100 101 return unless length $salt_bin == 16; 102 return unless length $iv_bin == 12; 103 return unless length $ct_bin == 72; 104 105 my $word_packed = pack_if_HEX_notation ($word); 106 107 my $new_hash = module_generate_hash ($word_packed, unpack ("H*", $salt_bin), unpack ("H*", $iv_bin), unpack ("H*", $ct_bin)); 108 109 return ($new_hash, $word); 110} 111 1121; 113