CTKlib

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

t/09-configuration.t		CTK::Configuration
t/10-log.t			CTK::Log
t/11-plugins.t			Plugins testing
t/12-app.t			CTK::App
t/13-void.t			Void tests
t/14-plugin-file.t		Plugin: File
t/15-flags.t			CTK::Util: Flags test
t/16-plugin-archive.t		Plugin: Archive
t/17-crypt-tcd04.t		Crypt: TCD04
t/18-crypt.t			Crypt
t/19-crypt-gpg.t		Crypt: GPG
t/20-plugin-net.t		Plugin: Net
t/21-sendmail.t			Sendmail testing
t/22-dbi.t			CTK::DBI
t/23-attrs.t			CTK::Util::read_attributes in the new edition
t/24-digest.t			Digest tests
t/25-plugins-ext.t		Extended plugins test (since 2.04)
t/26-filepid.t			CTK::FilePid
t/27-timeout.t			Timeout check
t/28-cgu-lvalue.t		LastValue for value method

lib/CTK/Crypt.pm  view on Meta::CPAN

=head1 NAME

CTK::Crypt - Cryptography frontend module

=head1 VERSION

Version 1.73

=head1 SYNOPSIS

    use CTK::Util qw/gpg_init gpg_encrypt gpg_decrypt/;

    my $gpg_instance = gpg_init(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

    gpg_encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $CTK::Crypt::ERROR );

    gpg_decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $CTK::Crypt::ERROR );

    tcd_encrypt( "file.txt", "file.tcd" )
        or die( $CTK::Crypt::ERROR );

    tcd_decrypt( "file.tcd", "file.txt" )
        or die( $CTK::Crypt::ERROR );

=head1 DESCRIPTION

Cryptography frontend module

=over 8

=item B<gpg_init>

    my $gpg_instance = gpg_init(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

Initialize GPG instance

See L<CTK::Crypt::GPG>

=item B<gpg_decrypt>

    $gpg_instance->decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $CTK::Crypt::ERROR );

GPG (PGP) Decrypting the files

See L<CTK::Crypt::GPG>

=item B<gpg_encrypt>

    $gpg_instance->encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $CTK::Crypt::ERROR );

GPG (PGP) Encrypting the files

See L<CTK::Crypt::GPG>

=item B<tcd_decrypt>

lib/CTK/Crypt.pm  view on Meta::CPAN

=item B<:all>

Will be exported all functions

=item B<:tcd04>

Will be exported following functions:

    tcd_encrypt, tcd_decrypt

=item B<:gpg>

Will be exported following functions:

    gpg_init, gpg_encrypt, gpg_decrypt

=back

=head1 HISTORY

See C<Changes> file

=head1 DEPENDENCIES

L<CTK::Crypt::GPG>, L<CTK::Crypt::TCD04>

lib/CTK/Crypt.pm  view on Meta::CPAN


use base qw/Exporter/;

use IO::File;
use CTK::Crypt::GPG;
use CTK::Crypt::TCD04;

use constant BUFFER_SIZE => 32 * 1024; # 32kB

@EXPORT_OK = (qw/
        gpg_init gpg_encrypt gpg_decrypt
        tcd_encrypt tcd_decrypt
    /);

%EXPORT_TAGS = (
        tcd04 => [qw/tcd_encrypt tcd_decrypt/],
        gpg   => [qw/gpg_init gpg_encrypt gpg_decrypt/],
        all   => [@EXPORT_OK],
    );

my $GPG_INSTANCE;

sub gpg_init {
    return $GPG_INSTANCE = CTK::Crypt::GPG->new(@_);
}
sub gpg_encrypt {
    $ERROR = "";
    my $st = $GPG_INSTANCE->encrypt(@_);
    $ERROR = $GPG_INSTANCE->error unless $st;
    return $st;
}
sub gpg_decrypt {
    $ERROR = "";
    my $st = $GPG_INSTANCE->decrypt(@_);
    $ERROR = $GPG_INSTANCE->error unless $st;
    return $st;
}
sub tcd_encrypt {
    my $filein = shift;
    my $fileout = shift;
    unless (defined($filein) && length($filein) && -e $filein) {
        $ERROR = sprintf("File not found \"%s\"", $filein // "");

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

CTK::Crypt - GPG Crypt backend

=head1 VERSION

Version 1.01

=head1 SYNOPSIS

    use CTK::Crypt::GPG;

    my $gpg = CTK::Crypt::GPG->new(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

    $gpg->encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $gpg->error );

    $gpg->decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $gpg->error );

=head1 DESCRIPTION

GPG Crypt backend

See L<http://www.gnupg.org> (GPG4Win - L<http://gpg4win.org>) for details

For start working with this module You need create public and private GPG keys:

    gpg --full-gen-key

Example of interaction (test account):

    > Anonymous
    > anonymous@example.com
    > Password: test
    < 58E79B320D135DEE
    < ADF81A296AAC9503A6135F258E79B320D135DEE

For show list of available keys run:

    gpg -k
    gpg -K

For export keys run:

    gpg --export -a -o mypublic.key "anonymous@example.com"
    gpg --export-secret-keys --batch --pinentry-mode loopback --passphrase "test" -a -o myprivate.key "anonymous@example.com"

=head2 new

    my $gpg = CTK::Crypt::GPG->new(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

=over 8

=item B<gpgbin>

GPG program

For example: "/usr/bin/gpg"

Default: gpg from PATH

=item B<gpghome>, B<homedir>

GPG homedir

For example: "/gpg/homedir"

Default: /tmp/gpgXXXXX

=item B<gpgconf>

Path to GPG config file (for options storing)

For example: "/gpg/homedir/gpg.conf"

Default: /tmp/gpgXXXXX/gpg.conf

=item B<gpgopts>, B<options>

GPG default options

For example: ["verbose", "yes"]

Default: ["verbose", "yes"],

=item B<publickey>, B<pubkey>, B<pubring>

Public key path

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

=item B<recipient>, B<keyid>, B<id>, B<user>, B<keygrip>

Email, user id, keyid, or keygrip

For example: "anonymous@example.com",

=back

=head2 decrypt

    $gpg->decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $gpg->error );

PGP file decrypting

=over 8

=item B<in>, B<filein>, B<filesrs>, B<infile>, B<src>

Source file (encrypted file)

=item B<out>, B<fileout>, B<filedst>, B<outfile>, B<dst>

Target file

=back

=head2 encrypt

    $gpg->encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $gpg->error );

PGP file encrypting

=over 8

=item B<in>, B<filein>, B<filesrs>, B<infile>, B<src>

Source file

=item B<out>, B<fileout>, B<filedst>, B<outfile>, B<dst>

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

Enable armor-mode (as text output): yes, on, 1, enable

For example: "yes"

Default: "no"

=back

=head2 error

    print $gpg->error;

Returns error string

=head1 HISTORY

See C<Changes> file

=head1 DEPENDENCIES

L<CTK::Util>, L<File::Temp>

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

=head1 TO DO

See C<TODO> file

=head1 BUGS

* none noted

=head1 SEE ALSO

L<CTK::Util>, L<http://www.gnupg.org>, L<GPG4Win|http://gpg4win.org>

=head1 AUTHOR

Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved

=head1 LICENSE

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

use vars qw/$VERSION/;
$VERSION = '1.01';

use Carp;
use CTK::Util qw(:API :FORMAT :UTIL :FILE );
use File::Temp qw();
use File::Spec;

use constant {
    # GPG (GNUPG)
    GPGBIN    => 'gpg',
    GPGCONF   => 'gpg.conf',
    GPGOPTS   => ["verbose", "yes"],
    GPGEXT    => ".asc",
};

sub new {
    my $class = shift;
    my ($gpgbin, $gpghome, $gpgconf, $gpgopts, $pubkey, $seckey, $pass, $recipient) =
    read_attributes([
        ['GPG','GPGBIN','BIN','CMD','COMMAND'],
        ['GPGHOME','GPGDIR','DIRGPG','HOMEGPG','HOMEDIR'],
        ['GPGCONF','CONFIG','CONF'],
        ['GPGOPTS','GPGOPTIONS','OPTIONS','OPTS'],
        ['PUBLIC','PUBLICKEY','PUP','PUBKEY','PUBRING'],
        ['PRIVATE','PRIV','PRIVATEKEY','SEC','SECKEY','SECRETKEY','PRIVKEY','PRIVRING','SECRING'],
        ['PASS','PASSWORD','PASSPHRASE','PASSW'],
        ['RECIPIENT','KEYID','ID','USER','KEYGRIP'],
    ], @_) if defined $_[0];
    $gpgbin ||= which(GPGBIN);
    my $tmpdir = File::Temp->newdir(TEMPLATE => 'gpgXXXXX', TMPDIR => 1) unless $gpghome;
    if ($gpghome) {
        preparedir($gpghome, 0700) or do {
            carp(sprintf("Can't prepare dir: %s", $gpghome));
            return undef;
        };
    } else {
        $gpghome = $tmpdir->dirname;
    }
    $gpgconf ||= File::Spec->catfile($gpghome, GPGCONF);
    $gpgopts ||= GPGOPTS;
    my @opts = ('# Do not edit this file');
    if (ref($gpgopts) eq 'ARRAY') { push @opts, @$gpgopts }
    else { push @opts, $gpgopts }
    fsave($gpgconf, join("\n", @opts)) or do {
        carp(sprintf("Can't save GPG conffile: %s", $gpgconf));
        return undef;
    };
    eval { chmod $gpgconf, 0600 };

    # Get version
    my @cmd = ();
    push(@cmd, $gpgbin, "--homedir", $gpghome, "--options", $gpgconf, "--version");
    my $err = "";
    my $out = execute( [@cmd], undef, \$err, 1 );
    my $version = $out && $out =~ /gpg.+?([0-9\.]+)\s*$/m ? $1 : 0;
    if ($version) {
        my $tv = pack("U*",split(/\./, $version));
        unless ($tv gt pack("U*", 2, 0)) {
            carp(sprintf("Incorrect GPG version v%vd. Require v2.0.0 and above", $tv));
            return undef;
        }
    }
    $out = "" if $version;

    # Import keys
    foreach my $key ($pubkey, $seckey) {
        next unless $key;
        next unless length($key);
        next unless -e $key;
        @cmd = ($gpgbin, "--homedir", $gpghome, "--options", $gpgconf);
        push @cmd, "--pinentry-mode", "loopback", "--passphrase", $pass if $pass && length($pass);
        push @cmd, "--import", $key;
        $out = execute( [@cmd], undef, \$err, 1 );
        unless ($recipient) {
            foreach my $t ($out, $err) {
                next unless $t;
                $recipient = $1 if $t =~ /key\s+([a-z0-9]+)\:/im;
                last if $recipient;
            }
        }
    }

    my $self = bless {
        gpgbin  => $gpgbin,
        homedir => $gpghome,
        tempdir => $tmpdir,
        gpgconf => $gpgconf,
        options => [@opts],
        cmd     => join(" ", @cmd),
        stdout  => $out,
        stderr  => $err,
        version => $version,
        pubkey  => $pubkey,
        seckey  => $seckey,
        password => $pass,
        recipient => $recipient,
        error => $recipient ? "" : "Incorrect recipient!",

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

    $self->{error} = "";
    $armor = isTrueFlag($armor);
    my $recipient = $self->{recipient};
    return 0 unless $recipient;
    unless (defined($inf) && length($inf) && -e $inf) {
        $self->{error} = sprintf("File not found: %s", $inf // "");
        return 0;
    }
    $outf = sprintf("%s%s", $inf, GPGEXT) unless defined($outf) && length($outf);

    my @cmd = ($self->{gpgbin}, "--homedir", $self->{homedir}, "--options", $self->{gpgconf}, "--always-trust");
    push(@cmd, "-r", $recipient);
    push(@cmd, "-a") if $armor;
    push(@cmd, "-o", $outf);
    push(@cmd, "-e", $inf);
    $self->{cmd} = join(" ", @cmd);
    my $err = "";
    my $out = execute( [@cmd], undef, \$err, 1 );
    $self->{stdout} = $out // '';
    $self->{stderr} = $err // '';

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

    $self->{error} = "";
    unless (defined($inf) && length($inf) && -e $inf) {
        $self->{error} = sprintf("File not found: %s", $inf // "");
        return 0;
    }
    unless (defined($outf) && length($outf)) {
        $self->{error} = "Incorrect output file";
        return 0;
    }

    my @cmd = ($self->{gpgbin}, "--homedir", $self->{homedir}, "--options", $self->{gpgconf}, "--always-trust");
    push(@cmd, "--pinentry-mode", "loopback", "--passphrase", $self->{password}) if $self->{password};
    push(@cmd, "-o", $outf);
    push(@cmd, "-d", $inf);
    $self->{cmd} = join(" ", @cmd);
    my $err = "";
    my $out = execute( [@cmd], undef, \$err, 1 );
    $self->{stdout} = $out // '';
    $self->{stderr} = $err // '';

    # Return

lib/CTK/Crypt/GPG.pm  view on Meta::CPAN

sub error {
    my $self = shift;
    return $self->{error} // '';
}


1;
__END__

List of keys:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --list-keys
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --list-secret-keys

Delete all keyrings:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --delete-secret-and-public-key 58E79B320D135DEE

Export keys to files:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --export -a -o mypublic.key 58E79B320D135DEE
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --export-secret-keys -a -o myprivate.key 58E79B320D135DEE

Encrypting:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --import ./mypublic.key
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --always-trust -r 58E79B320D135DEE -o README.asc -a -e README
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --delete-keys 58E79B320D135DEE

Decrypting:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --pinentry-mode loopback --passphrase "test" --import ./myprivate.key
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --always-trust --pinentry-mode loopback --passphrase "test" -o README.dec -d README.asc
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --batch --delete-secret-keys 58E79B320D135DEE

Password unset:
gpg --homedir /home/minus/mygpg --options /home/minus/mygpg/gpg.conf --edit-key 58E79B320D135DEE

lib/CTK/Plugin/Crypt.pm  view on Meta::CPAN


Version 1.01

=head1 SYNOPSIS

    use CTK;
    my $ctk = CTK->new(
            plugins => "crypt",
        );

    my $gpg_instance = $ctk->gpg_init(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

    $ctk->gpg_encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $self->error );

    $ctk->gpg_decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $self->error );

    $ctk->tcd_encrypt( "file.txt", "file.tcd" )
        or die( $self->error );

    $ctk->tcd_decrypt( "file.tcd", "file.txt" )
        or die( $self->error );

=head1 DESCRIPTION

Cryptography plugin

See L<https://www.gnupg.org/> (GPG4Win - L<https://www.gpg4win.org/>) for details

=head1 METHODS

=over 8

=item B<gpg_init>

    my $gpg_instance = $ctk->gpg_init(
        -gpgbin     => "/usr/bin/gpg",
        -gpghome    => "/gpg/homedir",
        -gpgconf    => "/gpg/homedir/gpg.conf",
        -gpgopts    => ["verbose", "yes"],
        -publickey  => "/path/to/public.key",
        -privatekey => "/path/to/private.key",
        -password   => "passphrase", # Key password
        -recipient  => "anonymous@example.com", # Email, user id, keyid, or keygrip
    ) or die("Can't create crypter");

Initialize GPG instance. NOTE! It is GLOBAL object!

For using self object please use L<CTK::Crypt::GPG> module

See L<CTK::Crypt::GPG>

=item B<gpg_decrypt>

    $ctk->gpg_decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $self->error );

GPG (PGP) Decrypting the files

See L<CTK::Crypt::GPG>

=item B<gpg_encrypt>

    $ctk->gpg_encrypt(
        -infile => "MyDocument.txt",
        -outfile=> "MyDocument.txt.asc",
        -armor  => "yes",
    ) or die( $self->error );

GPG (PGP) Encrypting the files

See L<CTK::Crypt::GPG>

=item B<tcd_decrypt>

    $ctk->gpg_decrypt(
        -infile => "MyDocument.txt.asc",
        -outfile=> "MyDocument.txt",
    ) or die( $self->error );

TCD04 Decrypting the files

See L<CTK::Crypt::TCD04>

=item B<tcd_encrypt>

lib/CTK/Plugin/Crypt.pm  view on Meta::CPAN

=head1 TO DO

See C<TODO> file

=head1 BUGS

* none noted

=head1 SEE ALSO

L<CTK>, L<CTK::Plugin>, L<CTK::Crypt>, L<GnuPG|https://www.gnupg.org/>, L<GPG4Win|https://www.gpg4win.org/>

=head1 AUTHOR

Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved

=head1 LICENSE

lib/CTK/Plugin/Crypt.pm  view on Meta::CPAN

=cut

use vars qw/ $VERSION /;
$VERSION = '1.01';

use base qw/CTK::Plugin/;

use CTK::Crypt ();

__PACKAGE__->register_method(
    method    => "gpg_init",
    callback  => sub {
    my $self = shift;
    return CTK::Crypt::gpg_init(@_);
});

__PACKAGE__->register_method(
    method    => "gpg_encrypt",
    callback  => sub {
    my $self = shift;
    my $status = CTK::Crypt::gpg_encrypt(@_);
    return $status if $status;
    $self->error($CTK::Crypt::ERROR);
    return 0;
});

__PACKAGE__->register_method(
    method    => "gpg_decrypt",
    callback  => sub {
    my $self = shift;
    my $status = CTK::Crypt::gpg_decrypt(@_);
    return $status if $status;
    $self->error($CTK::Crypt::ERROR);
    return 0;
});

__PACKAGE__->register_method(
    method    => "tcd_encrypt",
    callback  => sub {
    my $self = shift;
    my $status = CTK::Crypt::tcd_encrypt(@_);

t/12-app.t  view on Meta::CPAN

ok($ctk->conf("flag"), "Flag is true");
is(value($ctk->config(), "myinc/Test/val2"), "Blah-Blah-Blah", "myinc/Test/val2 eq Blah-Blah-Blah");

ok($ctk->configobj->status, "Congig status is ok") or diag($ctk->configobj->error);

if (-d '.svn' || -d '.git') {
    note(explain($ctk));
    note($ctk->foo);
}

#$ctk->gpg_decript("Blah-Blah-Blah");

1;

__END__

t/19-crypt-gpg.t  view on Meta::CPAN

my $dst = File::Spec->catdir("src", "dst");
ok(preparedir($dst), "Prepare $dst");
my $asc_file = File::Spec->catfile($dst, FILENAME_ASC);
my $dec_file = File::Spec->catfile($dst, FILENAME_DEC);

# Create test file with 10 lines
my @pool;
for (1..10) { push @pool, sprintf("%02d %s", $_, randchars( 80 )) };
ok(fsave(FILENAME_SRC, join("\n", @pool)), "Save random file");

my $gpg = new_ok( 'CTK::Crypt::GPG', [(
        -publickey  => File::Spec->catfile("src", PUBLIC_TEST_KEY),
        -privatekey => File::Spec->catfile("src", PRIVATE_TEST_KEY),
        -password   => PASSWORD,
    )] );
exit 1 unless $gpg;
#note(explain($gpg));

# Encrypt file
ok($gpg->encrypt(
        -infile => FILENAME_SRC,
        -outfile=> $asc_file,
        -armor  => "yes",
    ), "Encrypt file") or diag( $gpg->error );
#note(explain($gpg));

# Decrypt file
ok($gpg->decrypt(
        -infile => $asc_file,
        -outfile=> $dec_file,
    ), "Decrypt file") or diag( $gpg->error );

is(
    Digest::MD5->new->addfile(IO::File->new(FILENAME_SRC, "r"))->hexdigest,
    Digest::MD5->new->addfile(IO::File->new($dec_file, "r"))->hexdigest,
    "Files are identical"
);

1;

__END__



( run in 0.974 second using v1.01-cache-2.11-cpan-df04353d9ac )