roperl has asked for the wisdom of the Perl Monks concerning the following question:

I need to decrypt large pgp/gpg files

I can do this with GnuPG, but it calls an external gpg program binary ie "/usr/local/bin/gpg"

The Crytp:OpenPGP module does this with a pure perl implementation
However, the decrypt function returns the decrypted file into a scalar variable

open( my $fh, '>', 'pt.txt' ); my $pt = $pgp->decrypt(Filename => $file, Passphrase => $pp); $fh = $pt; close $fh;
This works fine with small files, but a large encrypted file (100MB) can return a huge plain text file (1.5 GB) This then will cause Out of Memory! error.
Is there any way to handle this using Crypt::OpenPGP?

Replies are listed 'Best First'.
Re: Using Crypt::OpenPGP with large files
by zentara (Cardinal) on Jul 25, 2017 at 12:30 UTC
    I can do this with GnuPG, but it calls an external gpg program binary ie "/usr/local/bin/gpg" ..... The Crytp:OpenPGP module does this with a pure perl implementation However, the decrypt function returns the decrypted file into a scalar variable

    My advice, since it's a huge secured file, is to run the /usr/local/bin/gpg binary from Perl, using system, qx, backticks, IPC3 or whatver method you choose. The c program will do it right and faster than perl on a huge file, and you won't have to worry about huge memory gains which come in a Perl program after using alot of memory. For example see: perl gpg system calls


    I'm not really a human, but I play one on earth. ..... an animated JAPH
      Using GnuPG already calls /usr/local/bin/gpg externally, you can see it running as a separate process
      #!/opt/perl/bin/perl -w #use strict; use GnuPG qw( :algo ); my $gpg = GnuPG->new(gnupg_path => "/usr/local/bin/gpg", homedir => "/ +home/rolivier/.gnupg"); my $encfile='/home/ro/big.testfile.gpg'; $outfile = $encfile; $outfile =~ s/.gpg//; my $pp='Passphrase'; $gpg->decrypt(ciphertext => $encfile, output => $outfile, passphrase = +> $pp);
      I'm thinking of using Crypt::OpenPGP for small files < 1MB and the GnuPG for the rest. The program I'm writing will be processing thousands of small files, so repeatedly calling an external process isn't the best solution. That's why I was looking for a pure-perl implementation.
        The program I'm writing will be processing thousands of small files, so repeatedly calling an external process isn't the best solution. That's why I was looking for a pure-perl implementation.

        If the module already calls /usr/local/bin/gpg externally, then you have a different problem. You need to be sure that you are not creating a new Crypt::OpenPGP object for each file, otherwise you will be causing alot of overhead. What you want to do is create 1 Crypt::OpenPGP object and reuse it. You must clear out all the old data in the object after each use. See

        7.27: How do I clear a package? Use this code, provided by Mark-Jason Dominus: sub scrub_package { no strict 'refs'; my $pack = shift; die "Shouldn't delete main package" if $pack eq "" || $pack eq "main"; my $stash = *{$pack . '::'}{HASH}; my $name; foreach $name (keys %$stash) { my $fullname = $pack . '::' . $name; # Get rid of everything with that name. undef $$fullname; undef @$fullname; undef %$fullname; undef &$fullname; undef *$fullname; } } Or, if you're using a recent release of Perl, you can just use the Symbol::delete_package() function instead.
        So now you can reuse that same opening of /usr/local/bin/gpg, which will speed things up and reduce memory usage. You would still have 1 memory problem however, because the perl object's memory usage will swell to the largest file size it encounters.

        So you may have to filter your files for size, to decide to feed them directly to the binary, or use the reusable module.

        There is also the possibility of running parallel processes in threads if you have a multicore computer. But that is a whole different thread on it's own, running gpg thru threads.

        1 last bit of advice, run all your decoding on a ramdisk if it is to be kept private. :-)


        I'm not really a human, but I play one on earth. ..... an animated JAPH
Re: Using Crypt::OpenPGP with large files
by thanos1983 (Parson) on Jul 24, 2017 at 23:01 UTC

    Hello roperl,

    Welcome to the monastery. I have never used the Crypt::OpenPGP but by reading the documentation why don't you the encrypted line one by one in the file and decrypt it?

    Sample of code from similar question Crypt::OpenPGP, encrypting messages using a public key file:

    $pgp = new Crypt::OpenPGP( SecRing => $private_file ); my $plaintext = $pgp->decrypt ( Data => $cyphertext, Passphrase => $pass, ) || die $pgp->errstr();

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      The input file a mostly in binary format, so processing 1 line at a time isn't possible
Re: Using Crypt::OpenPGP with large files
by thanos1983 (Parson) on Jul 25, 2017 at 08:55 UTC

    Hello again roperl,

    I do not know if you have managed to resolve your problem but I was trying to search through the web regarding your question and I found this article that I think is useful The problem of decrypting big files encrypted with openssl smime.

    It is not referring to OpenPGP but more to encryption limitations I assume are applied the same problems. From the link above:

    Yes you will hit that problem with large files. The S/MIME encrypt str +eams with a low memory overhead while decrypt does not stream and nee +ds the whole file in memory. It's a serious amount of effort to stream decrypt and +so far there hasn't been enough interest to do that.

    Reading it maybe it will assist you or other monks to have a better understanding. It is not a solution to your problem but more about general knowledge.

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Using Crypt::OpenPGP with large files
by Anonymous Monk on Jul 24, 2017 at 21:20 UTC
    Why are you using open/$fh?
      Is there anything wrong with that? Need to open $fh to output file and then print to the output file the plain text after it was decrypted. Still the issue is the decrypt function returns to variable as opposed to being able to pass output filehandle

        Well, you could just as well do this:

        $fh = $pgp->decrypt(Filename => $file, Passphrase => $pp);

        But depending on how that method works, you may not see any improvement. Worth a try though.

        Is there anything wrong with that? Need to open $fh to output file and then print to the output file the plain text after it was decrypted.

        But your code does not try to print anything to $fh, all it does is create an empty file ..

        Still the issue is the decrypt function returns to variable as opposed to being able to pass output filehandle

        Yeah decrypt doesn't do that

        You can make a feature request or bug report at rt://Crypt-OpenPGP ( bug-Crypt-OpenPGP@rt.cpan.org )

        It would be nice if decrypt didnt slurp giant files

A reply falls below the community's threshold of quality. You may see it by logging in.