Blockchain-Ethereum-Keystore
view release on metacpan or search on metacpan
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
use Carp;
use File::Slurp;
use JSON::MaybeXS qw(decode_json encode_json);
use Crypt::PRNG;
use Net::SSH::Perl::Cipher;
use Blockchain::Ethereum::Keystore::Key;
use Blockchain::Ethereum::Keystore::Keyfile::KDF;
sub new {
my ($class, %params) = @_;
my $self = bless {}, $class;
for (qw(cipher ciphertext mac version iv kdf id private_key)) {
$self->{$_} = $params{$_} if exists $params{$_};
}
return $self;
}
sub cipher {
shift->{cipher};
}
sub ciphertext {
shift->{ciphertext};
}
sub mac {
shift->{mac};
}
sub version {
shift->{version};
}
sub iv {
shift->{iv};
}
sub kdf {
shift->{kdf};
}
sub id {
shift->{id};
}
sub private_key {
shift->{private_key};
}
sub _json {
return shift->{json} //= JSON::MaybeXS->new(utf8 => 1);
}
sub import_file {
my ($self, $file_path, $password) = @_;
my $content = read_file($file_path);
my $decoded = $self->_json->decode(lc $content);
return $self->_from_object($decoded, $password);
}
sub _from_object {
my ($self, $object, $password) = @_;
my $version = $object->{version};
croak 'Version not supported' unless $version && $version == 3;
return $self->_from_v3($object, $password);
}
sub _from_v3 {
my ($self, $object, $password) = @_;
my $crypto = $object->{crypto};
$self->{cipher} = 'AES128_CTR';
$self->{ciphertext} = $crypto->{ciphertext};
$self->{mac} = $crypto->{mac};
$self->{version} = 3;
$self->{iv} = $crypto->{cipherparams}->{iv};
my $header = $crypto->{kdfparams};
$self->{kdf} = Blockchain::Ethereum::Keystore::Keyfile::KDF->new(
algorithm => $crypto->{kdf}, #
dklen => $header->{dklen},
n => $header->{n},
p => $header->{p},
r => $header->{r},
c => $header->{c},
prf => $header->{prf},
salt => $header->{salt});
$self->{private_key} = $self->_private_key($password);
return $self;
}
sub change_password {
my ($self, $old_password, $new_password) = @_;
return $self->import_key($self->_private_key($old_password), $new_password);
}
sub _private_key {
my ($self, $password) = @_;
return $self->private_key if $self->private_key;
my $cipher = Net::SSH::Perl::Cipher->new(
$self->cipher, #
$self->kdf->decode($password),
pack("H*", $self->iv));
my $key = $cipher->decrypt(pack("H*", $self->ciphertext));
return Blockchain::Ethereum::Keystore::Key->new(private_key => $key);
}
( run in 0.475 second using v1.01-cache-2.11-cpan-870870ed90f )