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::Mode::CBC; 12use Crypt::PBKDF2; 13use Digest::SHA qw (sha256 sha256_hex); 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 $iter = shift // 100000; 22 my $iv = shift // random_hex_string (2*16); 23 my $plain = shift // random_hex_string (2*1024); 24 25 my $b_iv = pack ('H*', $iv); 26 my $b_salt = pack ('H*', $salt); 27 my $b_plain = pack ('H*', $plain); 28 29 my $kdf = Crypt::PBKDF2->new 30 ( 31 hash_class => 'HMACSHA1', 32 iterations => $iter, 33 output_len => 32 34 ); 35 36 my $pass_hash = sha256 ($word); 37 my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); 38 my $cbc = Crypt::Mode::CBC->new ('AES', 0); 39 my $b_cipher = $cbc->encrypt ($b_plain, $key, $b_iv); 40 my $cipher = unpack ('H*', $b_cipher); 41 my $checksum = sha256_hex ($b_plain); 42 43 my $hash = '$odf$' . "*1*1*$iter*32*$checksum*16*$iv*16*$salt*0*$cipher"; 44 45 return $hash; 46} 47 48sub module_verify_hash 49{ 50 my $line = shift; 51 52 my ($hash, $word) = split (':', $line); 53 54 return unless defined $hash; 55 return unless defined $word; 56 57 my $word_packed = pack_if_HEX_notation ($word); 58 59 # tokenize 60 my @data = split ('\*', $hash); 61 62 return unless scalar @data == 12; 63 64 my $signature = shift @data; 65 my $cipher_type = shift @data; 66 my $cs_type = shift @data; 67 my $iter = shift @data; 68 my $cs_len = shift @data; 69 my $cs = shift @data; 70 my $iv_len = shift @data; 71 my $iv = shift @data; 72 my $salt_len = shift @data; 73 my $salt = shift @data; 74 my $unused = shift @data; 75 my $cipher = shift @data; 76 77 # validate 78 return unless $signature eq '$odf$'; 79 return unless $cipher_type eq '1'; 80 return unless $cs_type eq '1'; 81 return unless $cs_len eq '32'; 82 return unless $iv_len eq '16'; 83 return unless $salt_len eq '16'; 84 return unless $unused eq '0'; 85 return unless defined $cipher; 86 87 # decrypt 88 my $b_iv = pack ('H*', $iv); 89 my $b_salt = pack ('H*', $salt); 90 my $b_cipher = pack ('H*', $cipher); 91 92 my $kdf = Crypt::PBKDF2->new 93 ( 94 hash_class => 'HMACSHA1', 95 iterations => $iter, 96 output_len => 32 97 ); 98 99 my $pass_hash = sha256 ($word); 100 my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); 101 my $cbc = Crypt::Mode::CBC->new ('AES', 0); 102 my $b_plain = $cbc->decrypt ($b_cipher, $key, $b_iv); 103 my $plain = unpack ('H*', $b_plain); 104 105 my $new_hash = module_generate_hash ($word_packed, $salt, $iter, $iv, $plain); 106 107 return ($new_hash, $word); 108} 109 1101; 111