2015-02-11 253 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; 
    }