#!/usr/bin/env perl ## ## Author......: See docs/credits.txt ## License.....: MIT ## use strict; use warnings; use Crypt::CBC; use Crypt::PBKDF2; use Digest::Keccak qw (keccak_256_hex); sub module_constraints { [[0, 256], [40, 40], [-1, -1], [-1, -1], [-1, -1]] } sub module_generate_hash { my $word = shift; my $ethaddr = shift; my $encseed = shift; my $iv = ""; my $seed = ""; # setup pbkdf2 params: my $pbkdf2 = Crypt::PBKDF2->new ( hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256), iterations => 2000, output_len => 16 ); my $key = $pbkdf2->PBKDF2 ($word, $word); if (defined $encseed) { $iv = substr ($encseed, 0, 16); $encseed = substr ($encseed, 16); # AES-128-CBC decrypt: my $aes_cbc = Crypt::CBC->new ({ key => $key, cipher => "Crypt::Rijndael", iv => $iv, literal_key => 1, header => "none", keysize => 16 }); $seed = $aes_cbc->decrypt ($encseed); } else { $iv = random_bytes (16); $seed = random_bytes (592); # AES-128-CBC encrypt: my $aes_cbc = Crypt::CBC->new ({ key => $key, cipher => "Crypt::Rijndael", iv => $iv, literal_key => 1, header => "none", keysize => 16 }); $encseed = $aes_cbc->encrypt ($seed); } my $digest = keccak_256_hex ($seed . "\x02"); my $hash = sprintf ("\$ethereum\$w*%s*%s*%s", unpack ("H*", $iv . $encseed), $ethaddr, substr ($digest, 0, 32)); return $hash; } sub module_verify_hash { my $line = shift; my ($hash, $word) = split (':', $line); return unless defined $hash; return unless defined $word; my $signature = substr ($hash, 0, 12); return unless ($signature eq "\$ethereum\$w\*"); my @data = split ('\*', $hash); return unless scalar (@data) == 4; shift @data; my $encseed = pack ("H*", shift @data); my $ethaddr = shift @data; my $bpk = pack ("H*", shift @data); my $word_packed = pack_if_HEX_notation ($word); my $new_hash = module_generate_hash ($word_packed, $ethaddr, $encseed, $bpk); return ($new_hash, $word); } 1;