Sending Encrypted Email S/MIME with PHP

久未见 提交于 2020-01-07 04:49:09

问题


I have been looking a lot online but I didn't find an answer, is it possible to send encrypted emails S/MIME using PHP? if it is, how? (im using cakephp 2.x)

Thank you very much in advance


回答1:


I managed to find a solution to this using PHPMailer, It applies to regular PHP as well. It will sign and encrypt the email, I couldn't find a way to do both with PHPMailer (sign and encrypt) only sign so I added some code to class.phpmailer.php. It stills need to add some error handling in case of an encryption error but so far works good.

for CakePHP 2.x:

Download PHPMailer and add it to your Vendors folder (project_name/app/vendor)

Add this line at the beginning of your function:

App::import('Vendor','PHPMailer/PHPMailerAutoload');

From here its the same for PHP or CakePHP:

 $mail = new PHPMailer(); 
 $mail->setFrom('from_who@email', 'Intranet');
 //Set who the message is to be sent to 
 $mail->addAddress('to_who@email', 'Ricardo V'); 
 //Set the subject line 
 $mail->Subject = 'PHPMailer signing test';
 //Replace the plain text body with one created manually 
 $mail->Body = "some encrypted text...";
 //Attach an image file 
 $mail->addAttachment('D:/path_to_file/test.pdf'); 
 $mail->sign( 
     'app/webroot/cert/cert.crt', //The location of your certificate file 
     'app/webroot/cert/private.key', //The location of your private key
 file 
     'password', //The password you protected your private key with (not 
    //the Import Password! may be empty but parameter must not be omitted!) 
     'app/webroot/cert/certchain.pem', //the certificate chain.
     '1', //Encrypt the email as well, (1 = encrypt, 0 = dont encrypt)
     'app/webroot/cert/rvarilias.crt'//The location of public certificate 
   //to encrypt the email with.
 ); 
 if (!$mail->send()) { 
     echo "Mailer Error: " . $mail->ErrorInfo; 
 } else { 
     echo "Message sent!"; 
 } 

Then we need to make some changes to class.phpmailer.php

replace the lines from 2368 to 2390 with:

$sign = @openssl_pkcs7_sign(
                    $file,
                    $signed,
                    'file://' . realpath($this->sign_cert_file),
                    array('file://' . realpath($this->sign_key_file), 
$this->sign_key_pass),
                    null,
                    PKCS7_DETACHED,
                    $this->sign_extracerts_file
                );
                if ($this->encrypt_file == 1) {
                    $encrypted = tempnam(sys_get_temp_dir(), 'encrypted');
                    $encrypt = @openssl_pkcs7_encrypt(
                    $signed,
                    $encrypted,
                    file_get_contents($this->encrypt_cert_file),
                    null,
                    0,
                    1
                );
                if ($encrypted) {
                    @unlink($file);
                    $body = file_get_contents($encrypted);
                    @unlink($signed);
                    @unlink($encrypted);
                    //The message returned by openssl contains both headers
and body, so need to split them up
                    $parts = explode("\n\n", $body, 2);
                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
                    $body = $parts[1];
                } else {
                    @unlink($file);
                    @unlink($signed);
                    @unlink($encrypted);
                    throw new phpmailerException($this->lang('signing') .
openssl_error_string());
                }
                } else {

                if ($signed) {
                    @unlink($file);
                    $body = file_get_contents($signed);
                    @unlink($signed);
                    //The message returned by openssl contains both headers
 and body, so need to split them up
                    $parts = explode("\n\n", $body, 2);
                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
                    $body = $parts[1];
            } else {
                    @unlink($file);
                    @unlink($signed);
                    throw new phpmailerException($this->lang('signing') .  
 openssl_error_string());
            }

                   } 

            }

then look for:

public function sign($cert_filename, $key_filename, $key_pass,   
$extracerts_filename = '')
{
    $this->sign_cert_file = $cert_filename;
    $this->sign_key_file = $key_filename;
    $this->sign_key_pass = $key_pass;
    $this->sign_extracerts_file = $extracerts_filename;
}

and change it for:

public function sign($cert_filename, $key_filename, $key_pass,
$extracerts_filename = '', $and_encrypt ='0', $encrypt_cert = '')
    {
        $this->sign_cert_file = $cert_filename;
        $this->sign_key_file = $key_filename;
        $this->sign_key_pass = $key_pass;
        $this->sign_extracerts_file = $extracerts_filename;
        $this->encrypt_file = $and_encrypt;
        $this->encrypt_cert_file = $encrypt_cert;
    }

look for:

protected $sign_extracerts_file = '';

and add these lines after it:

protected $encrypt_cert = '';
protected $and_encrypt = '';

With these changes to phpmailer you can send a signed email or a signed and encrypted email. It works with attachments too.

I hope it is help ful to somebody.

*for regular php just don't add the line:

App::import('Vendor','PHPMailer/PHPMailerAutoload');


来源:https://stackoverflow.com/questions/42830049/sending-encrypted-email-s-mime-with-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!