http://qs321.pair.com?node_id=1062044

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

Hi there Monks!
I am trying to encrypt a file using Crypt::OpenPGP, when it runs it does not give me any errors, it just hangs there. Can any one take a look at my code and see where I am missing something.
#!/usr/bin/perl use strict; use warnings; use File::Basename; use Crypt::OpenPGP; my $ring = Crypt::OpenPGP::KeyRing->new( Data => qq^-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.8 (SunOS) mQGiBFDr..... -----END PGP PUBLIC KEY BLOCK-----^ ); my $datafile = "original.csv"; # Get just name of the original file to name the new encrypted file. my ( $encrypted ) = fileparse( $datafile, "\.[^.]*" ); # $name, $path, + $suffix open( INFILE, "< $datafile" ) or die "Could not open csv file - $!"; my $plaintext = <INFILE>; close INFILE; $ring->read; my $kb = $ring->find_keyblock_by_index(0); my $cert = $kb->encrypting_key; my $pgp = Crypt::OpenPGP->new( Compat => 'GnuPG' ); my $ct = $pgp->encrypt( Key => $cert, Data => $plaintext, Armour => 1 +) or die "ERROR: " . $pgp->errstr; open( OUTFILE, "> $encrypted.pgp" ) or die "Could not open file for en +crypted data - $!"; print OUTFILE $ct; close OUTFILE;
Thanks for looking!

Replies are listed 'Best First'.
Re: Code hanging with Crypt OpenPGP
by davido (Cardinal) on Nov 11, 2013 at 21:32 UTC

    I don't know what system you're on, but the pari library is known to be difficult to get installed correctly on many systems (Debian, for example). And Crypt::OpenPGP depends on Crypt::RSA, which depends on Math::Pari, somewhere in its dependency chain.

    Alt::Crypt::RSA::BigInt was designed by Dana Jacobsen to install and masquerade in place of Crypt::RSA. Just installing the "Alt" version of the module changes the dependency automatically. The "BigInt" in the module's title is a clue that it, internally, uses Math::BigInt, which can use gmp for fast big integer support. The gmp toolchain installs more reliably on a larger percentage of systems than pari. I wish I had the development conversation threads relating to this still handy... probably somewhere in my Gmail. :)

    So, to summarize, in a test environment, install libgmp, Alt::Crypt::RSA::BigInt, and then Crypt::OpenPGP. Then run your code and see if you still get a silent crash. Hopefully not. ;)


    Dave

Re: Code hanging with Crypt OpenPGP
by kennethk (Abbot) on Nov 11, 2013 at 21:45 UTC
    One issue with your posted code, though I would be surprised if this is your issue, is that you are only pulling in one line of your plaintext - to pull a full file into a scalar, you should either set binmode or slurp (my $plaintext = do{local $/;<INFILE>}). Maybe you're encoding a null string and thus your output is much shorter than you expect?

    It's possible, though seems unlikely, that you've got some strange characters in your opens (your posted code shouldn't suffer from that issue). 3-argument open will handle any escapes that that need handling. Swapping to Indirect Filehandles, that would be:

    #!/usr/bin/perl use strict; use warnings; use File::Basename; use Crypt::OpenPGP; my $ring = Crypt::OpenPGP::KeyRing->new( Data => qq^-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.8 (SunOS) mQGiBFDr..... -----END PGP PUBLIC KEY BLOCK-----^ ); my $datafile = "original.csv"; # Get just name of the original file to name the new encrypted file. my ( $encrypted ) = fileparse( $datafile, '\.[^.]*' ); # $name, $path, + $suffix open( my $in, "<", $datafile ) or die "Could not open csv file - $!"; my $plaintext = do{local $/;<$in>}; close $in; $ring->read; my $kb = $ring->find_keyblock_by_index(0); my $cert = $kb->encrypting_key; my $pgp = Crypt::OpenPGP->new( Compat => 'GnuPG' ); my $ct = $pgp->encrypt( Key => $cert, Data => $plaintext, Armour => 1 +) or die "ERROR: " . $pgp->errstr; open( my $out, ">", "$encrypted.pgp" ) or die "Could not open file for + encrypted data - $!"; print $out $ct; close $out;

    Also note "\.[^.]*" doesn't mean what you likely thought, though it still works for your purposes for the given code.

    Lastly, if you have your literal key pasted in the block for $ring, your use of qq delimiters might result in some weird interpolation, though that would likely have gotten caught by strict.

    Hope some of this helps...

    Update: Fixed typo, as per below.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Shouldn't this line be :
      my $plaintext = do{local $/;<$in>};
      Instead of:
      my $plaintext = do{local $/;<INFILE>};
      Still hangs on this line for me:
      my $ct = $pgp->encrypt( Key => $cert, Data => $plaintext, Armour => 1 +) or die "ERROR: " . $pgp->errstr;
        What kind of debugging environment do you have set up? Since Crypt::OpenPGP is pure-Perl, you should be able to isolate the particular operation in encrypt that's causing trouble.

        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: Code hanging with Crypt OpenPGP
by danaj (Friar) on Nov 12, 2013 at 03:40 UTC

    I just tried this on a 5.18.0 install, with kennethk's fix for pulling in the whole file, and it worked for me (Ubuntu). It encrypted various test files, and gpg 1.4.11 was able to decrypt them to the original input.

    While David is right that Alt::Crypt::RSA::BigInt fixes a bunch of issues on some machines, I don't believe it has any impact here. It's calling Crypt::Rijndael::encrypt via Crypt::OpenPGP::CFB::encrypt.

    I thought it might be computation time, but a 7MB csv file encrypted in about 0.5 seconds (with the XS Crypt::Rijndael so the actual encryption was about 3% of the total time taken). The time consuming parts of that half second on my machine were crc24, CFB encrypt (the Perl wrapper around the block encrypt), and Zlib deflate.

    My next thought was hanging waiting for Crypt::Random to get entropy from /dev/random, but it looks like it's reading 282 bytes from /dev/urandom, and the latter shouldn't block.

    Without knowing more (e.g. is the O/S Linux, Windows, Solaris, Sunos 4.1, etc.? What version of Perl? What versions of Crypt::OpenPGP and friends?) I'm not sure.

      I am using Linux and I still can not have it working, it still hangs and it does not show any erros, what code are you using that works for you? Can you posted here?
      Thanks!

        Here is the code I'm using, with minimal changes from the OP (no fixing two argument open, etc.).

        I generated a new key using gpg 1.4.11: "gpg --gen-key" (default RSA/RSA, 2048-bit, no expire). Then export with "gpg --armor --export ........" with the public key identifier.

        I also plugged in Bruce Schneier's PGP key and it happily encrypts things for me (though I can't decrypt them of course)

        When I tried the key you posted, I got an error in $ring->read. I get the same error if I use a key generated with openssl (because it isn't a PGP key).

        #!/usr/bin/perl use strict; use warnings; use File::Basename; use Crypt::OpenPGP; my $ring = Crypt::OpenPGP::KeyRing->new( Data => qq^-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.11 (GNU/Linux) mQENBFKCi0wBCADAEhnYIcTEqusZo0atDDEzidDVgr5WxGulhf92k5ziSXdcwPfn B4cG8tKuuUeSUpPWAe5zgKN4wwkI1fQvdET8bYFppAKQwnkDpHXUhvX+3lYCxf2m Nm/6mZcCZQEb/JdY2D7cTYMu20IX4uakthmVMOGpIFrwwfrKd5cMrD1UkOf7D80d aou17nJIM2PSO0tVkwiImpiDPxR9/zC01EIgMVxlU0Rqc+viBfaZQ61IDobY+Guf XXVa3uA6jwTRIVyFKtfj7DyrLq81LcUuyOFeFLAXu5nfdjUQ93oW/jo53+h51fuK 8RQ5mQ4ThKtsaEMvFfQ4hoqbiZhrWcwOaQ5rABEBAAG0J0RhbmEgSmFjb2JzZW4g KFRlc3Qga2V5KSA8ZGFuYUBhY20ub3JnPokBOAQTAQIAIgUCUoKLTAIbAwYLCQgH AwIGFQgCCQoLBBYCAwECHgECF4AACgkQswvVk2rxbey6xAf/ZioN0eaRcP3Bl/xS k/EbPRRExWveNvKRy6CaDVXTgL1PUJ9mtY5Pi+mHzJ7CqXK0FmtaipkrwKFKfekz AKK2K0A7wvzXi2pMncP1iw58lgF+nNT0GAabYsaiyIx/lkhZ+A+R9veSXqBaPSKR jozQKzdXfiUa+RhjgQuBXiR74NqhY6g/T0Ah2dMm+j1rw3Hk+9oCPNpOFDeBKTnw 8o4s1JlQVqhzVMdZQHaQo0dJLpkBqjBLHn0q46UJu13KwOIlAakj8uVGyGXLfWbu saub2kzCjU+MN/ZAkJIkUO3OqFB/s7l8viMf7rtG0pVdCBtItaiizquiv8BruyZK nlTOGLkBDQRSgotMAQgArFn8WDPUz9qXK58c5rZnNUXBLGF/1g69MKgRnZC2KV0+ e+/i0R2f7F6k7teaNy1sjZnagf9UP7PoyUcN1ROwvJ7Gw2qVoYZlJrs6+cWfwChE ui31UvcsBvY4ht+vs5TAJ81IKZOCryLS1hySLLA7YvyyyR2A9bI6rsjJ282Uct0q wLM31a8geW1C8pMC4ZQTzuLEdUlG9fzazo0FI3layFGoiZ+sMc6y5eBYz6Ozx8vv guvkBDqss7VmWOkPqvbWK9+5AwrFgAy680Fbib7ets+ZKqPlyaZYjGAxIJNMS7pZ 5sgy9ePgKSOuHYPQphuOTFyaxJu7lRfNC9WIiE22vQARAQABiQEfBBgBAgAJBQJS gotMAhsMAAoJELML1ZNq8W3sO0wH+wY/WkuQSIyAksyGABhBzyltga9WKV0SmpTT BbupBRLMYg+/GubDfLU/irM7O4K0hBj/8UtGYMnG1RiJ4Kk+rCyn/6CPwYPLI+Fd EJjVh1MPcwWPxXWFAX3v1uH8A5Xyi6uZDW14QfhMKJ77bDqzIpdmxwStfQgwWHv4 nseqiaaaXriAlMZagZLBARYTb80PWV0LR61EO3DzZlHYRDbq4QlvwPg3lLugTabK FtLrMQEGtTKwXZI8Or7LmcRELid2LyJOAGPS2YgpF0czyyB1Pym1K+mybmFO0Ikn 4Gg6UfkmL9WdC3xLHHWNJFYn9iMXFBlFOyPr8G1Kuq6bq05G3b4= =j1aQ -----END PGP PUBLIC KEY BLOCK-----^ ); my $datafile = "original.csv"; # Get just name of the original file to name the new encrypted file. my ( $encrypted ) = fileparse( $datafile, "\.[^.]*" ); # $name, $path, + $suffix open( INFILE, "< $datafile" ) or die "Could not open csv file - $!"; #my $plaintext = <INFILE>; my $plaintext = do{local $/;<INFILE>}; close INFILE; $ring->read; my $kb = $ring->find_keyblock_by_index(0); my $cert = $kb->encrypting_key; my $pgp = Crypt::OpenPGP->new( Compat => 'GnuPG' ); my $ct = $pgp->encrypt( Key => $cert, Data => $plaintext, Armour => 1 +) or die "ERROR: " . $pgp->errstr; warn "writing to $encrypted.pgp\n"; open( OUTFILE, "> $encrypted.pgp" ) or die "Could not open file for en +crypted data - $!"; print OUTFILE $ct; close OUTFILE;
Re: Code hanging with Crypt OpenPGP
by ProtoFly (Initiate) on Jun 30, 2016 at 16:17 UTC
    Stumbled on this thread while investigating a problem similar. Running almost the exact same code, I have discovered that encrypting with certain keys work, and certain keys hang. I've traced the hang to ElGamal.pm, in a loop starting on line 59, the condition for exit is never satisfied -with some keys-.
    While (1) { last if Math::BigInt::bgcd($k, $p_minus1) == 1; k++; }
    Not even remotely sure how to resolve. -Darryl
      I ran into this when we updated to CentOS 7.2 and went from perl 5.10 to 5.16. $p is too big for perl to subtract 1 from and results in inf. Still trying to figure out why it worked before but for now using Math::BigInt to calculate p_minus1 will fix it:
      sub gen_k { my ($p) = @_; ## XXX choose bitsize based on bitsize of $p my $bits = 198; my $p_minus1 = Math::BigInt->new($p)->bsub(1); my $k = Crypt::OpenPGP::Util::get_random_bigint($bits); while (1) { last if Math::BigInt::bgcd($k, $p_minus1) == 1; $k++; } $k; }