使用 X509Certificate2 验证证书密码
Validate certificate password using X509Certificate2
我想验证证书密码。目前我有基于处理 CryptographicException 和检查异常消息的代码。但是这种方法依赖于英语文化信息。
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;
}
我一直在寻找其他解决方案来验证证书密码,但没有成功。
验证证书密码的正确方法是什么?
如果有任何想法,我将不胜感激...
我会选择 PFXVerifyPassword and PFXIsPFXBlob 本机函数。虽然,它需要一个 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;
}
}
}
由于我工作的公司不允许使用原生 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;
}
几个月后我找到了更好的解决方案(也许是最好的)。它基于 CryptographicExcaption 的 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
我想验证证书密码。目前我有基于处理 CryptographicException 和检查异常消息的代码。但是这种方法依赖于英语文化信息。
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;
}
我一直在寻找其他解决方案来验证证书密码,但没有成功。
验证证书密码的正确方法是什么?
如果有任何想法,我将不胜感激...
我会选择 PFXVerifyPassword and PFXIsPFXBlob 本机函数。虽然,它需要一个 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;
}
}
}
由于我工作的公司不允许使用原生 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;
}
几个月后我找到了更好的解决方案(也许是最好的)。它基于 CryptographicExcaption 的 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