How to encrypt a message using a public key and email it?
Results 1 to 10 of 10

Thread: How to encrypt a message using a public key and email it?

  1. #1
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830

    How to encrypt a message using a public key and email it?

    I've been trying to concoct a PHP script to take a sensitive message, encrypt it using someone's public key and email it. I've looked at three different approaches I've found through google search and none seems to work

    Approach 1
    The first uses openssl_pkcs7_encrypt and I followed the sample script here. Two problems. First, the encryption is not very strong:
    openssl_pkcs7_encrypt() takes the contents of the file named infile and encrypts them using an RC2 40-bit cipher so that they can only be read by the intended recipients specified by recipcerts.
    40-bit cipher doesn't sound particularly strong.
    Secondly, the script doesn't work:
    PHP Code:
    $headers = array(
        
    "From" => "sender@example.com",
        
    "To" => "recipient@example.com",
        
    "Subject" => "Encrypted mail test",
        
    "X-Mailer" => "PHP/".phpversion()
    );

    define("PUBLIC_KEY_PATH""/path/to/public_key.pub");

    // Get the public key certificate.
    $pubkey file_get_contents(PUBLIC_KEY_PATH);

    // Remove some double headers for mail()
    $headers_msg $headers;
    unset(
    $headers_msg['To'], $headers_msg['Subject']);

    $data "This email is Encrypted!\nYou must have my certificate to view this email!\nMe\n";

    //write msg to disk
    $msgfile "/path/to/msg.txt";
    file_put_contents($msgfile$data);

    // Encrypt message
    $encrypted_msgfile "/path/to/encrypted_msg.txt";
    $crypt_result openssl_pkcs7_encrypt($msgfile$encrypted_msgfile$pubkey$headers_msgPKCS7_TEXT1);
    if (
    $crypt_result === FALSE) {
        die (
    "encryption failed\n");
    }

    // Separate headers and body for mail()
    $data file_get_contents($encrypted_msgfile);

    $parts explode("\n\n"$data2);

    // Send mail
    mail($headers['To'], $headers['Subject'], $parts[1], $parts[0]); 
    It dies with this error:
    Code:
    error:0906D066:PEM routines:PEM_read_bio:bad end line
    encryption failed
    I'm not certain, The problem might be with the $pubkey param I supply to openssl_pkcs7_encrypt -- this file is apparently not x.509. The key file looks something like this:
    Code:
    -----BEGIN PGP PUBLIC KEY BLOCK-----
    Version: GnuPG v2.0.17 (MingW32)
    
    mQINBFE2oIsBEACo1d7vsGdmWJqUHSHsDcOH8ZL+YJbNrghnvRe2V1QNF83JsF+C
    LHfL3piH4MZ1FEQsAyUfqn7fqagIU0KrrsT4MeCR8msYAE64cTkwkT4J4Y4wEybj
    
    ...etc..
    
    Pqvo9g9u2Vswm11CHZs9QsXm/9+5qf9Ww3ycZfmAOM8jkrtpO9gdpDF9zfmCQiVc
    HX3gATz3HZoheHhOIA==
    =Xnkl
    -----END PGP PUBLIC KEY BLOCK-----
    Approach 2
    Although it doesn't mention email, I tried using the mcrypt sample code given in the manual for mcrypt_module_open. That script does encrypt and decrypt some data but it does so by generating its own key for some reason:
    PHP Code:
    /* Create key */
    $key substr(md5('very secret key'), 0$ks); 
    And the key is quite short (32 chars in length). It's not clear to me if I would be allowed to use a public key belonging to the recipient. Additionally, the encrypted message appears to be binary instead of ASCII armored of base 64 encoded and it also lacks any sort of emailable headers to describe the encryption technique or whatever that would lend any clues to a remote email client. I tend to doubt a mail client would be able to make sense of the cipher. The documentation on mcrypt really seems to assume you know exactly what it is for.

    Approach 3
    The last approach is from an IBM article and relies on command line use of gpg to create the encrypted message. While I believe this approach would generate nice useful informative header information about the encrypted content, the script doesn't seem to allow me to specify a public key file directly and instead relies on me to manipulate the appropriate keyrings to manage keys for both the sender and the recipient. This script fails:
    PHP Code:
    $from "sneakyimp"// local username on my ubuntu box
    $to "recipient@example.com"// some email address

    //cut the message down to size, remove HTML tags
    $messagebody "Here is my encrypted message.\nI have defined it in PHP and encrypted it using the example at http://www.ibm.com/developerworks/library/os-php-encrypt/index.html\n\nHope this works!";
    $escaped_body escapeshellarg($messagebody);

    $gpg_path '/usr/bin/gpg'// this may vary from distro to distro
    $home_dir '/path/to/test/dir';
    $user_env 'sneakyimp';

    $cmd "echo $escaped_body | HOME=$home_dir USER=$user_env $gpg_path.
        
    "--quiet --no-secmem-warning --encrypt --sign --armor " .
        
    "--recipient $to --local-user $from";

    echo 
    "cmd:\n";
    echo 
    $cmd "\n\n";

    $message_body = `$cmd`;

    mail($to,'Encrypted Message'$message_body,"From:$from\r\n"); 
    The approach obviously doesn't let me manually specify the location of the public key file for recipient@example.com This script produces an error:
    Code:
    cmd:
    echo 'Here is my encrypted message.
    I have defined it in PHP and encrypted it using the example at http://www.ibm.com/developerworks/library/os-php-encrypt/index.html
    
    Hope this works!' | HOME=/path/to/test/dir USER=sneakyimp /usr/bin/gpg --quiet --no-secmem-warning --encrypt --sign --armor --recipient recipient@example.com --local-user sneakyimp
    
    gpg: skipped "sneakyimp": secret key not available
    gpg: [stdin]: sign+encrypt failed: secret key not available

    Can anyone refer me to a working PHP script that accomplishes this? Or perhaps help me sort the issue? It seems to me it would be very useful to have a script that can send an encrypted message. I'm very much interested in portability and would like to avoid any steps where one must manipulate the keyring belonging to a user and one could instead specify a specific key file, etc. Any advice would be much appreciated.
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  2. #2
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    OK so I pulled out my copy of Bruce Schneier's Applied Cryptography (an really good book) and has a very helpful section on Privacy-Enhanced Mail(PEM) which I've been looking at. Turns out PEM is not just way to encrypt things but it describes a variety of privacy-related protocols. To summarize Schneier:
    PEM is the Internet Privacy-Enhanced Mail standard adopted by the Internet Architecture Board (IAB) to provide secure electronic mail over the Internet...The PEM protocols provide for encryption, authentication, and key management.
    The basic idea is that it describes protocols for sending encrypted and/or signed messages while also describing what has gone into encrypting and/or signing them. It supports both symmetric and public key encryption. The Wikipedia link above says that it was not widely adopted due to its reliance on a centralized root CA.

    I think this cocktail of encryption-plus-protocol is what I'm after. Schneier also has a section on PGP (which uses web-of-trust rather than centralized CA) but details about the protocol look pretty light.

    Seems to me that if I want to have PHP sending these messages, I will probably have two choices:
    1) concoct awkward CLI stuff in PHP and use exec to manipulate key rings and such to get gpg to encrypt my messages (and then take care to shred and/or cleanup the file system to make sure my sensitive messages don't hang around
    2) use mcrypt or some other PHP extension to encrypt my messages and then write PHP code to build out the appropriate email-friendly protocol aspects described by PEM and/or PGP such that the message, when it arrives at somebody's mail client, will be decipherable by something like Enigmail or some other secure mail client/plugin.

    Surely someone has done this in PHP before?
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  3. #3
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    Also, just found this:
    http://www.php.net/manual/en/function.gnupg-encrypt.php

    It's one of those modules with really spare documentation -- not much detail. And not many examples.
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  4. #4
    High Energy Magic Dept. NogDog's Avatar
    Join Date
    Aug 2006
    Location
    Ankh-Morpork
    Posts
    13,885
    Looks like Swiftmailer has some encryption support: http://swiftmailer.org/docs/messages...rypted-message
    Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett

    "But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html


    eBookworm.us

  5. #5
    Pedantic Curmudgeon Weedpacket's Avatar
    Join Date
    Aug 2002
    Location
    General Systems Vehicle "Thrilled To Be Here"
    Posts
    21,842
    Quote Originally Posted by sneakyimp
    It's one of those modules with really spare documentation -- not much detail. And not many examples.
    You might have to go to the GPGME manual and try to map what's there onto the PECL extension's interface. The tedious part of course is that the GPGME manual is written for the benefit of the PECL extension's writer, rather than the extension's user.
    Last edited by Weedpacket; 03-08-2013 at 05:36 PM.
    THERE IS AS YET INSUFFICIENT DATA FOR A MEANINGFUL ANSWER
    FAQs! FAQs! FAQs! Most forums have them!
    Search - Debugging 101 - Collected Solutions - General Guidelines - Getting help at all

  6. #6
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    Thanks, weedpacket, for the info.

    For anyone who is interested, I was able to install gnupg, a PECL extension, by doing the following on my Ubuntu 11.04 machine:
    Code:
    # required by pecl to install gnupg:
    sudo apt-get install libgpgme11-dev
    # luckily, pecl command is available on my workstation so I don't have to compile on my own
    sudo pecl install gnupg
    Then, create a new ini file, /etc/php5/conf.d/gnupg.ini containing this one line:
    Code:
    extension=gnupg.so
    Restart apache
    Code:
    sudo /etc/init.d/apache2 restart
    Check phpinfo() output for gnupg support.
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  7. #7
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    OK so I've been reading that link Weedpacket sent along and see that it has key management functions but I don't see all of those implemented in the PHP extension -- e.g., I can't see any way to list one's keys.

    I also get the impression that apache will need its own keyring. Interestingly, assuming the role of www-data on my ubuntu workstation didn't exactly have the desired effect:
    Code:
    sneakyimp@ubuntu-64:/var/www/erep_v2$ sudo su www-data
    [sudo] password for sneakyimp: 
    $ whoami
    www-data
    $ gpg --list-keys
    gpg: fatal: can't create directory `/var/www/.gnupg': Permission denied
    secmem usage: 0/0 bytes in 0/0 blocks of pool 0/32768
    I wonder how secure it is to keep keys in apache's keyring and for apache's keyring to be in /var/www? I expect I'll just be importing public keys from elsewhere so it sounds reasonably safe to me. I suppose I would feel a bit safer if it were not in /var/www but I don't know of any PHP.ini settings or apache settings that might let me put it somewhere else.
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  8. #8
    Pna lbh ernq guvf¿
    Join Date
    Jul 2004
    Location
    Kansas City area
    Posts
    19,393
    What is www-data's home directory? IIRC, that's the first (only?) default location it read/writes the '.gnupg' directory (which seems to be a common paradigm for many other *nix apps).

    EDIT: Try exporting the env variable 'GNUPGHOME' and pointing it somewhere other than your 'www' directory.

  9. #9
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    Quote Originally Posted by bradgrafelman View Post
    What is www-data's home directory? IIRC, that's the first (only?) default location it read/writes the '.gnupg' directory (which seems to be a common paradigm for many other *nix apps).
    Code:
    sneakyimp@ubuntu-64:/var/www/erep_v2$ sudo su www-data
    [sudo] password for sneakyimp: 
    $ ls -dl ~
    drwxr-xr-x 18 root root 4096 2013-01-18 13:54 /var/www
    It would appear that the home dir for www-data is /var/www (which on my machine is owned by root:root). Seems like it would be quite easy for the .gnupg directory to find itself in the web root of some domain in this location and that doesn't sound particularly secure -- if www-data has any private keys. On the other hand, I just looked at the contents of the files in my ~/.gnupg directory and it looks at least to be binary, possibly encrypted.
    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

  10. #10
    Senior Member
    Join Date
    Apr 2003
    Location
    Silver Lake
    Posts
    4,830
    woot! I have run this script from the command line on my workstation and it results in an encrypted message being sent using my gmail account. If I use Thunderbird (with Enigmail installed) to check my gmail account, I receive the message and decrypt it via the available OpenPGP functionality. I do get a notice/warning/error in Thunderbird that the signature cannot be verified but this is because I did not sign the encrypted message before sending it. It occurs to me that I don't know whether to use a public key or private key for signing messages.

    Anyway, this script imports a public key into somebody's keyring:
    PHP Code:
    <?php

    // to send encrypted mail to someone, you must first add their public key to your keyring
    // it will end up in the keyring of the user who runs this script (e.g., www-data or sneakyimp
    // in my case, depending on whether I run it from CLI or via Apache)


    // path to a file containing a recently created public key.
    // NOTE that I created this key on my windows machine
    // using Enigmail/OpenPGP functions and saved it in a file
    // on my Ubuntu workstation using SSH
    define("PUBLIC_KEY_PATH""/home/sneakyimp/cryptmail/recipient_public_key.pub");

    // import the key into your keyring (uses OOP style)
    // importing a key twice will not cause an error and will again
    // return an array.
    $gpg = new gnupg();
    $public_data file_get_contents(PUBLIC_KEY_PATH);
    $info $gpg->import($public_data);
    var_dump($info);
    Once you've done that, you should be able to see the imported key in your keyring. This command is helpful:
    Code:
    gpg --list-keys --fingerprint
    To get information on the key using PHP, you can refer to it using a variety of different identifiers.
    PHP Code:
    // get key info (uses procedural style)
    $gpg gnupg_init();
    // use the 32-byte full fingerprint, or the 8-byte short Key ID,
    // even partial owner names will work if the key is one suitable for encryption
    // obviously, the more specific you are, the less like you are to get something wonky
    $info gnupg_keyinfo($gpg'23A423BE');
    print_r($info); 
    Once the public key is in your keyring, you can use it to encrypt a message and send it via mail. This script requires PEAR::Mail to be installed but worked like a charm for me and sent the email message via a gmail account:
    PHP Code:
    try {
        
    $gpg = new gnupg();
        
    $gpg -> seterrormode(gnupg::ERROR_EXCEPTION); // throw an exception in case of an error
        
    $gpg -> setarmor(1); // enable armored output -- results in ASCII text rather than binary data;
        
    $gpg->addencryptkey("23A423BE"); // this is my public Key Id.
    //    $gpg->addencryptkey("recipient@example.com"); // this type of reference can also work YMMV

        // this is encrypted, but not signed.  you also need a private key to sign.    
        
    $encrypted $gpg->encrypt("Jaith, this is that secret message I was a-talking about");


        
    // code that follows requires you to have PEAR mail installed    
        
    require_once "Mail.php";

        
    $params = array(
            
    "host" => "smtp.gmail.com",
            
    "port" => 587,
            
    "auth" => TRUE,
            
    "username" => "sender@gmail.com",
            
    "password" => "someP4ssW0rd",
            
    "debug" => TRUE
        
    );
        
    $smtp Mail::factory('smtp'$params);
        if (
    PEAR::isError($smtp)){
            throw new 
    Exception("Unable to create pear MAIL object");
        }
        
    $headers = array(
            
    "From" => "sender@gmail.com",
            
    "Sender" => "sender@gmail.com",
            
    "Reply-to" => "sender@gmail.com"
        
    );
        
    $send_result $smtp->send("recipient@example.com.com"$headers$encrypted);
        if (
    $send_result !== TRUE){
            echo 
    "send failure:\n";
            
    var_dump($send_result);
            echo 
    "\n\n";
        }
        
        echo 
    "\n\nTHAT IS ALL\n\n";
    } catch (
    Exception $e) {
        echo 
    "error:" $gpg->geterror();
        die(
    "Exception:" $e->getMessage());

    IMPORTANT: STOP using the mysql extension. Use mysqli or pdo instead.
    World War One happened 100 years ago. Visit Old Grey Horror for the agony and irony.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •