2014-09-04 115 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