Blockchain-Ethereum

 view release on metacpan or  search on metacpan

lib/Blockchain/Ethereum/Keystore/File.pm  view on Meta::CPAN

package Blockchain::Ethereum::Keystore::File;

use v5.26;
use strict;
use warnings;

# ABSTRACT: Ethereum keystore file abstraction
our $AUTHORITY = 'cpan:REFECO';    # AUTHORITY
our $VERSION   = '0.021';          # VERSION

use Carp;
use JSON::MaybeXS;
use Crypt::PRNG;
use Crypt::Mode::CTR;
use Crypt::Digest::Keccak256 qw(keccak256);
use Scalar::Util             qw(blessed);
use Data::UUID;

use Blockchain::Ethereum::Key;
use Blockchain::Ethereum::Keystore::KDF;

my $json = JSON::MaybeXS->new(
    utf8      => 1,
    pretty    => 1,
    canonical => 1
);

sub from_key {
    my ($class, $key) = @_;

    croak 'key must be a Blockchain::Ethereum::Key instance'
        unless blessed $key && $key->isa('Blockchain::Ethereum::Key');

    my $self = bless {private_key => $key}, $class;
    return $self;
}

sub from_file {
    my ($class, $file_path, $password) = @_;

    my $self = bless {}, $class;

    my $content;
    {
        open my $fh, '<:raw', $file_path
            or croak "Could not read file '$file_path': $!";
        local $/;    # Enable slurp mode
        $content = <$fh>;
        close $fh;
    }
    my $decoded = $json->decode(lc $content);

    croak 'Version not supported'                        unless $decoded->{version} && $decoded->{version} == 3;
    croak 'Password is required to decrypt the keystore' unless defined $password;
    $self->{password} = $password;

    return $self->_from_v3($decoded);
}

sub cipher {
    shift->{cipher} //= Crypt::Mode::CTR->new('AES', 1);
}

sub ciphertext {
    my $self = shift;
    $self->{ciphertext} //= $self->_generate_ciphertext;
}

sub mac {
    my $self = shift;
    $self->{mac} //= $self->_generate_mac;

}

sub version {
    shift->{version} //= 3;
}

sub iv {
    my $self = shift;
    $self->{iv} //= $self->_generate_random_iv;
}

sub kdf {
    my $self = shift;
    $self->{kdf} //= $self->_generate_kdf;
}

sub id {
    my $self = shift;
    $self->{id} //= $self->_generate_id;
}

sub private_key {
    shift->{private_key};
}

sub password {
    shift->{password};
}

sub _from_v3 {
    my ($self, $object) = @_;

    my $crypto = $object->{crypto};

    $self->{ciphertext} = $crypto->{ciphertext};
    $self->{mac}        = $crypto->{mac};
    $self->{iv}         = $crypto->{cipherparams}->{iv};
    $self->{version}    = $object->{version};
    $self->{id}         = $object->{id};

    my $header = $crypto->{kdfparams};

    $self->{kdf} = Blockchain::Ethereum::Keystore::KDF->new(
        algorithm => $crypto->{kdf},     #
        dklen     => $header->{dklen},



( run in 1.351 second using v1.01-cache-2.11-cpan-39bf76dae61 )