在許多關於單獨簽署或加密電子郵件的討論中,沒有任何一個真正討論過同時簽署和加密電子郵件的痛苦。
*** 您先做什麼?先簽署再加密?還是先加密再簽署?
根據 RFC 2311,您可以先加密再簽署,或先簽署再加密。但是,這取決於您正在為其編寫程式的客戶端。以我的經驗,在 Outlook 2000 中,它偏好先加密再簽署。而在 Outlook 2003 中,則是先簽署再加密。一般來說,您會希望先簽署再加密,因為從郵件的角度來看,這似乎最合乎邏輯。您首先簽署一封信,然後將其放入信封。如果您以它不喜歡的順序執行此操作,某些客戶端會抱怨,因此您可能需要進行實驗。
*** 同時執行簽署和加密的範例。
當您執行第一個函式時,請勿在標頭陣列參數中放入任何標頭,您需要將其放入您要執行的第二個函式中。如果您將標頭放入第一個函式中,則第二個函式會將其從郵件伺服器中隱藏起來。您不希望這樣。在這裡,我將先簽署再加密。
<?
// 設定郵件標頭。
$headers = array("To" => "someone@nowhere.net",
"From" => "noone@somewhere.net",
"Subject" => "已簽署和加密的訊息。");
// 先簽署訊息
openssl_pkcs7_sign("msg.txt","signed.txt",
"signing_cert.pem",array("private_key.pem",
"password"),array());
// 取得公開金鑰憑證。
$pubkey = file_get_contents("cert.pem");
// 加密訊息,現在放入標頭。
openssl_pkcs7_encrypt("signed.txt", "enc.txt",
$pubkey,$headers,0,1);
$data = file_get_contents("enc.txt");
// 分離標頭和內文,以便與 mail 函式一起使用
// 不幸但必要,否則我們會有兩組標頭
// 而且電子郵件用戶端不會解碼附件
$parts = explode("\n\n", $data, 2);
// 發送郵件 (Headers 參數中的標頭會覆蓋為 To 和 Subject 參數產生的標頭)
// 為 To 和 Subject 參數產生的標頭)
mail($mail, $subject, $parts[1], $parts[0]);
?>
請注意,如果您使用一個從磁碟擷取資料的函式,以便在程式中的另一個函式中使用,請記住您可能使用了 explode("\n\n",$data,2) 函式,這可能會移除標頭和訊息內容之間的間距。
當您取得簽署的訊息並將其輸入到加密部分時,您必須記住,行距也必須作為訊息本文的一部分輸入!如果您計劃先簽署然後加密,請勿將簽署的標頭輸出作為標頭陣列參數的一部分輸入到加密中!簽署的輸出應保留為要加密的訊息本文的一部分。(如果您正在執行加密然後簽署的相反操作,情況也是如此。)以下範例說明如何將簽署和加密函式製作成可重複使用的常式,然後呼叫以簽署和加密訊息。
*** 從常式函式執行簽署和加密的範例,以透過程式碼重複使用。
這是錯誤的!
<?
// 陣列 [0] 包含訊息的標頭。[1] 包含訊息的已簽署內文。
$signedOutputArray = signMessage($inputMessage,$headers);
// 陣列 [0] 包含訊息的標頭和簽署。
// 陣列 [1] 包含沒有簽署標頭的加密訊息內文。
$signedAndEncryptedArray = encryptMessage($signedOutputArray[1],
$signedOutputArray[0]);
mail($emailAddr,$subject,$signedAndEncryptedArray[1],
$signedAndEncryptedArray[0]);
?>
這是正確的!
<?
// 陣列 [0] 包含簽署的標頭。
// 陣列 [1] 包含訊息的已簽署內文。
$signedOutputArray = signMessage($inputMessage,array());
// 陣列 [0] 包含訊息的標頭。
// 陣列 [1] 包含已簽署訊息及其簽署標頭的加密內容。
$signedAndEncryptedArray =
encryptMessage($signedOutputArray[0] . "\n\n" . $signedOutputArray[1],$headers);
mail($emailAddr,$subject,$signedAndEncryptedArray[1],
$signedAndEncryptedArray[0]);
?>