2014-09-04 50 views
0

我正在使用PHP實現S/Mime解密。我得到了什麼至今:無法解密已簽名的S/Mime消息

$keys = array("public"=>$atm."/public-keys/".$usr.".smime", 
     "private"=>$atm."/private-keys/".$usr.".smime"); 
    if(!file_exists($keys["public"])) die("Public Key not found"); 
    if(!file_exists($keys["private"])) die("Private Key not found"); 
    $public = file_get_contents($keys["public"]); 
    $private = file_get_contents($keys["private"]); 

    switch($_GET["debug"]) 
    { 
     case "encrypt": 
     { 
      $outfile = realpath("demo-msg/out.txt"); 
      $outfile_signed = realpath("demo-msg/out.signed.txt"); 
      $infile = realpath("demo-msg/in.txt"); 

      file_put_contents($infile,$msg); 
      $adddata = array("To" => "XXX", "From: Demo Name <XXX>", "Subject" => "Demo Subject"); 
      if (openssl_pkcs7_encrypt($infile, $outfile, $public, $adddata)) 
      { 
       //$info = file_get_contents($outfile); 
       echo "winenc & transfer<br>\n"; 
       file_put_contents($infile, file_get_contents($outfile)); 
       //if(openssl_pkcs7_sign($outfile,$outfile_signed,$public,$private,$adddata, PKCS7_BINARY)) echo "winsign"; 
       //else echo "failsign"; 
      } 
      else echo "Failed Encryption"; 
      exit; 
     } 
     default: 
     { 
      $outfile2 = realpath("demo-msg/out2.txt"); 
      $outfile = realpath("demo-msg/out.txt"); 
      $infile = realpath("demo-msg/smime.p7m"); 
      //$infile = realpath("demo-msg/in.txt"); 

      if(openssl_pkcs7_verify($infile)) echo "verified<br>\n"; //tried: openssl_pkcs7_verify($infile,$PKCS7_DETACHED, tmpfile(), array(), array(), $outfile) 
      else die("invalid sig"); 

      if(openssl_pkcs7_decrypt($infile, $outfile2, $public, $private)) //tried: openssl_pkcs7_decrypt($outfile, $outfile2, $public, $private) 
      { 
       echo "dec win:".file_get_contents($outfile2); 
      } 
      else echo "Oh oh! Decryption failed!"; 
      exit; 
     } 
    } 

什麼這個片段已經可以信息:

  • 加密消息
  • 解密加密消息(自行創建)
  • 解密加密的郵件(Office 2010)只要它沒有簽字

現在,我想要解密已簽名的消息(因爲它通常只有一步)。問題:

  • 如果我第一次嘗試解密,它會返回帶有不同頭的加密消息。多次解密導致相同的結果。
  • 我的想法是使用驗證命令的$ content - 參數(openssl_pkcs7_verify)。您可以在代碼註釋中看到我的嘗試。

不過,我沒有任何線索第二次嘗試可能會出現什麼問題。任何幫助,將不勝感激!

回答

1

對自己說話。

錯誤,我在腳本製作:

  • 驗證返回-1(錯誤),但我處理它爲真(成功)。驗證從未奏效。
  • 驗證顯然是錯誤的。 DETACHED是一個常量,而不是一個變量。 「extracert」參數需要一個有效的文件作爲包含有效簽名的字符串。雖然,我的想法是正確的(使用「內容」參數取消簽名)。
  • 簽名和加密

令我誤會了的樣子,簽名處理(和驗證製成)。 我認爲消息被加密,然後簽名。它可以就是這樣,但很多工具,包括Office2010首先簽名消息,然後加密它。這樣你就不能在解密之前檢查簽名,並且必須在解密後解除簽名

你可以在下面看到我的調試代碼。這將有助於解決您在解決此問題時遇到的解密問題。

  $test = openssl_pkcs7_verify($infile, PKCS7_DETACHED); //just to see that it doesn't work 
      echo "signature is ".$test."\n<br>".openssl_error_string(); 

      $dec = openssl_pkcs7_decrypt($infile, $outfile, $public, $private); 
      echo "<br><br>\n\ndec is ".$dec."\n<br>".openssl_error_string()."\n<br>".file_get_contents($outfile); 

      $test = openssl_pkcs7_verify($outfile, PKCS7_DETACHED, $tmp, array(), $tmp, $outfile2); 
      echo "<br><br>\n\nsignature2 is ".$test."\n<br>".openssl_error_string()."\n<br>".file_get_contents($outfile2); 
+1

感謝您報告回來。這將解決你的*編程錯誤*。但是請注意,默認情況下PHP似乎使用RC2加密和40位密鑰(即,如果您不知道密鑰,解密甚至是瞬時的)。此外,如果切換到AES-CBC編碼,則應首先驗證,然後進行解密(即簽名應在簽名的消息上),否則將容易受到(例如)填充Oracle攻擊。被警告說「有效」並不意味着「現在已經安全」。 – 2014-09-06 14:15:56

+0

感謝您的回覆。儘管如此,我並不確定如何處理這些信息。首先:你正在談論加密,而我正在處理解密。第二:你不提示如何改變編碼。第三:我很確定我已經閱讀了很多客戶首先簽名的多個來源,然後進行加密。因此,你的方式將無法正常工作。更多信息將會很棒:) – 2014-09-06 15:03:42

+1

在密碼學界有許多關於簽名/加密或加密/簽名的討論。如果您在傳輸協議中使用CBC模式進行加密,如果您不首先驗證簽名(並且這是您首先嚐試實現的目標),那麼您將很快失去機密性。如果你只解密,那麼你只能解密發送給你的內容。請注意,以這種方式解密的內容可能因爲應用PKCS#7(CMS)而不安全 - 還要檢查/記錄所使用的實際配置。 – 2014-09-06 15:23:08