http://qs1969.pair.com?node_id=257240

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

I need to encrypt a string using asymmetric keys and a passphrase. I would like to use something like Crypt::OpenPGP, but I don't see the functionality I'm looking for. Basically, I want to take an input string of 16 chars (credit card number) and encrypt it with a public key. The number should only be decrypted by using the private key and the passphrase.

I've looked at Crypt::OpenPGP, as well as some of the other cipher modules (like Crypt::Blowfish), but they either focus on encrypting files (versus stdin/stdout), or they use symmetric keys and passphrases, which aren't an option... I want the passphrase to be kept secret, not available in the source code.

Perhaps I could tie a filehandle to the string? Any suggestions?

-fp

Replies are listed 'Best First'.
Re: Using Asymmetric keys for Encryption
by benn (Vicar) on May 11, 2003 at 15:47 UTC
    from the Crypt::OpenPGP manual...
    $pgp->encrypt (%args) %args can contain: * Data - The plaintext to be encrypted. This should be a simple scala +r containing an arbitrary amount of data. Data is optional; if unspecified, you should specify a filename (see F +ilename, below).
    So you should just be able to call
    $pgp->encrypt(Data=>$credit_card_number,Recipients=>$key_id,Armour => +1,);
    Cheers,
    Ben
Re: Using Asymmetric keys for Encryption
by broquaint (Abbot) on May 11, 2003 at 15:44 UTC
    I'm a bit clueless on the crypto front, but as for operating on a string as though it were a file you can always use IO::Scalar, or if you're working with perl5.8.0, just use the new functionality of open e.g
    # using IO::Scalar tie *FH, 'IO::Scalar', \my $str = $somenumber; # using open() open(my $fh, '<', \my $str = $somenumber);

    HTH

    _________
    broquaint

Re: Using Asymmetric keys for Encryption
by derby (Abbot) on May 12, 2003 at 00:35 UTC
    That's the whole reason I wrote Getting Started with GnuPG and GPG. The write-up was a generalization of the Credit Card encryption scheme we used to use (but since then we've moved on to using a realtime payment gateway and we never hold in permanent storage the CC number).

    -derby

      Yeah, this is the client's decision. If I had my druthers, it would use a merchant gateway right now. As it is, that will probably be something for them to upgrade to later on. Thanks for the link! :)

      -fp
Re: Using Asymmetric keys for Encryption
by hardburn (Abbot) on May 11, 2003 at 19:49 UTC

    I want the passphrase to be kept secret, not available in the source code.

    Only way around this is to put the passphrase in a seperate file which you read out of each time your program runs. The file should be only be readable by the username your software runs under. You can run the passphrase through SHA1 first and set that value as the passphrase, so at least the passphrase wouldn't be in plaintext.

    I know, this isn't the best solution. It's mearly the only solution. In a perfect world, a human would manually enter the passphrase every time. This doesn't sound like an option for you, so I present this flawed but useable solution instead.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      Actually, you're referring to symmetric keys. I'm talking about asymmetric keys where the passphrase is embedded in the private key.

      I've since managed to get it working properly, although the ciphertext has to be directed into a file, and that file read back in to decrypt. I expect this is due to some incompatibility (or my ignorance of) the formatting types between the terminal and Perl's handling of scalars. I don't think this will be a problem once I output the data to a db table.

      For archival sakes, here are the scripts I've used for testing of encrypt() and decrypt():
      #!/usr/bin/perl # gpg.pl use Crypt::OpenPGP; my $string = $ARGV[0]; my $pgp = Crypt::OpenPGP->new; my $ciphertext = $pgp->encrypt( Data => $string, Recipients => 'Test User', Armour => 1, ); open(OUT, ">testfile"); print OUT $ciphertext, "\n"; close(OUT);
      ------------------------
      #!/usr/bin/perl # gupg.pl use Crypt::OpenPGP; my $pgp = Crypt::OpenPGP->new; my ($plaintext) = $pgp->decrypt( Filename => 'testfile', Passphrase => 'password', ); die "Decryption failed: ", $pgp->errstr unless $plaintext; print $plaintext, "\n";

      Update:
      I've managed to test and verify that writes/reads to database also work. Here is the updated code using Data to read in the ciphertext:
      #!/usr/bin/perl # gpg.pl use Crypt::OpenPGP; use DBI; my $string = $ARGV[0]; my $dbh = DBI->connect("DBI:mysql:pgpdb:localhost","user","password"); my $insert_stmt = 'insert into pgptable (card) values (?)'; my $sth = $dbh->prepare($insert_stmt); my $pgp = Crypt::OpenPGP->new; my $ciphertext = $pgp->encrypt( Data => $string, Recipients => 'Test User', Armour => 1, ); $sth->execute($ciphertext) || die $dbh->stderr;
      -------------------------
      #!/usr/bin/perl # gupg.pl use Crypt::OpenPGP; use DBI; my $dbh = DBI->connect("DBI:mysql:pgpdb:localhost","user","password"); my $select_query = 'select card from pgptable where id=?'; my $sth = $dbh->prepare($select_query); my $pgp = Crypt::OpenPGP->new; $sth->execute('1') || die $dbh->stderr; my $data = ($sth->fetchrow_hashref)->{'card'}; my ($plaintext) = $pgp->decrypt( Data => $data, Passphrase => 'passphrase', ); die "Decryption failed: ", $pgp->errstr unless $plaintext; print $plaintext, "\n";