App-locket

 view release on metacpan or  search on metacpan

lib/App/locket/Locket.pm  view on Meta::CPAN

    $reader =~ s/^\s*[|<]//;
    my $pipe = $reader;
    CORE::open( my $cipher, '-|', $pipe );
    my $plainstore = join '', <$cipher>;
    chomp $plainstore;
    return "$plainstore\n";

    die "*** Unknown/invalid reader ($reader)";
}

sub load {
    my $self = shift;
    my $plainstore = $self->plainstore;
    my $store;
    try {
        if ( $plainstore =~ m/^\s*\{/ )
                { $store = $JSON->decode( $plainstore ) }
        else    { $store = YAML::XS::Load( $plainstore ) }
    };
    die sprintf "*** Unable to parse store (%d)", length $plainstore if !$store;
    return App::locket::Store->new( store => $store );
}

sub reload {
    my $self = shift;
    $self->clear_plainstore;
    $self->clear_store;
    $self->store;
}

# ~
# Cipher
# ~

sub random ($) {
    my $length = shift;
    return makerandom_octet Length => $length, Strength => 1;
}

sub generate_keylet {
    my $self = shift;
    return { 
        master_seed => random 32,
        transform_seed => random 32,
        transform_count => 50_000,
        iv => random 16,
    };
}

sub generate_cipher {
    my $self = shift;
    my $keylet = shift;
    my $passphrase = shift;

    my $key_cipher = Crypt::Rijndael->new( $keylet->{ master_seed }, Crypt::Rijndael::MODE_ECB );
    my $key = sha256 $passphrase;
    $key = $key_cipher->encrypt( $key ) for 1 .. $keylet->{ transform_count };
    $key = sha256 $key;
    $key = sha256 $keylet->{ transform_seed }, $key;

    my $cipher = Crypt::Rijndael->new( $key, Crypt::Rijndael::MODE_CBC() );
    $cipher->set_iv( $keylet->{ iv } );

    return $cipher;
}

sub encrypt {
    my $self = shift;
    my $keylet = shift;
    my $passphrase = shift;
    my $plaintext = shift;

    my $cipher = $self->generate_cipher( $keylet, $passphrase );

    my $base64 = encode_base64 $plaintext, '';
    $base64 .= '=' x ( 16 - length( $base64 ) % 16 );
    return $cipher->encrypt( $base64 );
}

sub decrypt {
    my $self = shift;
    my $keylet = shift;
    my $passphrase = shift;
    my $ciphertext = shift;

    my $cipher = $self->generate_cipher( $keylet, $passphrase );

    my $base64 = $cipher->decrypt( $ciphertext );
    return decode_base64 $base64;
}

sub pickle {
    my $self = shift;
    my $keylet = shift;
    my $passphrase = shift;
    my $plaintext = shift;
    my %options = @_;

    my $plaintext_digest = sha256_hex $plaintext;

    my $pickle_keylet = { %$keylet };
    $_ = unpack 'h*', $_ for @$pickle_keylet{qw/ master_seed transform_seed iv /};

    my $pickle = {
        keylet => $pickle_keylet,
        plaintext_digest => $plaintext_digest,
        ciphertext => encode_base64( $self->encrypt( $keylet, $passphrase, $plaintext ), '' ),
    };

    if ( $options{ json } ) {
        $pickle = $JSON->encode( $pickle );
    }

    return $pickle;
}

sub unpickle {
    my $self = shift;
    my $passphrase = shift;
    my $pickle = shift;
    my %options = @_;



( run in 1.181 second using v1.01-cache-2.11-cpan-e1769b4cff6 )