2015-02-11 254 views
0

我想验证证书密码。此时我有基于处理CryptographicException并检查异常消息的代码。但这种方法依赖于英文文化信息。使用X509Certificate2验证证书密码

public bool VerifyPassword(byte[] fileContent, string password) 
    { 
     try 
     { 
      var certificate = new X509Certificate2(fileContent, password); 
     } 
     catch (CryptographicException ex) 
     { 
      if (ex.Message.StartsWith("The specified network password is not correct.")) 
      { 
       return false; 
      } 

      throw; 
     } 

     return true; 
    } 

我一直在寻找其他解决方案如何验证证书密码,但没有成功。

如何验证证书密码的正确方法是什么?

我将不胜感激任何想法...

回答

2

几个月后,我发现更好的解决方案(也许是最好的)。它基于CryptograhpicExcaption的HResult值。

static bool VerifyPassword(byte[] fileContent, string password) 
{ 
    try 
    { 
     // ReSharper disable once UnusedVariable 
     var certificate = new X509Certificate2(fileContent, password); 
    } 
    catch (CryptographicException ex) 
    { 
     if ((ex.HResult & 0xFFFF) == 0x56) 
     { 
      return false; 
     }; 

     throw; 
    } 

    return true; 
} 

所有HRESULTS(系统错误代码)文档可在:https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx

0

我会PFXVerifyPasswordPFXIsPFXBlob本地函数去。虽然它需要一个p/invoke,但它是一个真正的交易。

C#签名和样本代码:

using System; 
using System.IO; 
using System.Runtime.InteropServices; 

namespace ClassLibrary1 { 
    class CryptoAPI { 
     [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern Boolean PFXIsPFXBlob(
      [In]CRYPTOAPI_BLOB pPFX 
     ); 
     [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern Boolean PFXVerifyPassword(
      [In] CRYPTOAPI_BLOB pPFX, 
      [MarshalAs(UnmanagedType.LPWStr)] 
      [In] String szPassword, 
      [In] UInt32 dwFlags 
     ); 
     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
     public struct CRYPTOAPI_BLOB { 
      public UInt32 cbData; 
      public IntPtr pbData; 
     } 
    } 

    public class Program { 
     public static Boolean TestPfxPwd(Byte[] rawData, String password) { 
      // check for input data 
      if (rawData == null) { throw new ArgumentNullException("rawData"); } 
      // allocate a buffer in an unmanaged memory to store PFX content 
      IntPtr pbData = Marshal.AllocHGlobal(rawData.Length); 
      // copy PFX content to allocated buffer 
      Marshal.Copy(rawData, 0, pbData, rawData.Length); 
      // instantiate CRYPTOAPI_BLOB structure as it will be used 
      // to call both functions 
      CryptoAPI.CRYPTOAPI_BLOB blob = new CryptoAPI.CRYPTOAPI_BLOB { 
       cbData = (UInt32)rawData.Length, 
       pbData = pbData 
      }; 
      // determine if input byte array represents a PFX blob: 
      if (!CryptoAPI.PFXIsPFXBlob(blob)) { 
       // release unmanaged resources before leaving method 
       Marshal.FreeHGlobal(pbData); 
       throw new InvalidDataException("Input data is not valid PFX message."); 
      } 
      // call the PFXVerifyPassword function and store results in a temporary variable 
      Boolean retValue = CryptoAPI.PFXVerifyPassword(blob, password, 0); 
      // release unmanaged resources before leaving method 
      Marshal.FreeHGlobal(pbData); 
      // return pfx match status 
      return retValue; 
     } 
    } 
} 
+1

感谢您的例子。我不知道本地的Windows API。但我的公司(我工作)有限制,以避免使用本机窗口API。 – 2015-02-12 08:29:23

+0

由于大约一半的.NET(Cryptography命名空间的高达90%)是本地函数的包装,我没有看到本地函数的大问题。 – Crypt32 2015-02-12 08:41:12

+0

我明白了。但具体来说,X509Certificate2类在Mono中有自己的实例。我们的客户不应该依赖于Windows环境。这不是我的错。这是生意。另一个观点是你有什么保证微软不会改变原生API? – 2015-02-12 10:10:34

1

由于该公司为我不行允许使用原生Windows API的事实,我有一个解决方案 - >运行验证与InvariantCulture的新线程。它将适用于所有.Net语言突变。

下面是代码示例:

public bool VerifyPassword(byte[] fileContent, string password) 
    { 
     CheckParameters(fileContent, password); 
     var isPasswordVerified = false; 

     var verificationThread = new Thread(() => isPasswordVerified = VerifyPasswordWithUsCulture(fileContent, password)) 
     { 
      CurrentUICulture = CultureInfo.InvariantCulture 
     }; 

     verificationThread.Start(); 
     verificationThread.Join(); 

     return isPasswordVerified; 
    } 

    static bool VerifyPasswordWithUsCulture(byte[] fileContent, string password) 
    { 
     try 
     { 
      // ReSharper disable once UnusedVariable 
      var certificate = new X509Certificate2(fileContent, password); 
     } 
     catch (CryptographicException ex) 
     { 
      if (ex.Message.StartsWith("The specified network password is not correct.")) 
      { 
       return false; 
      } 

      throw; 
     } 

     return true; 
    }