Reputation: 3420
What should be the format (.pfx, .cer or something else) of the file here in the first parameter?
public X509Certificate2(
string fileName,
SecureString password,
X509KeyStorageFlags keyStorageFlags
)
More context :
I am getting following error while trying to get a certificate using the following function -
Function:
public static X509Certificate2 AuthenticationCertificate(string AuthenticationCertificateAsBase64String, string AuthenticationCertificatePassword)
{
if (!string.IsNullOrEmpty(AuthenticationCertificateAsBase64String) &&
AuthenticationCertificatePassword != null)
{
Console.WriteLine("AuthenticationCertificateAsBase64String: " + AuthenticationCertificateAsBase64String);
Console.WriteLine("AuthenticationCertificatePassword: " + AuthenticationCertificatePassword);
return new X509Certificate2(Convert.FromBase64String(AuthenticationCertificateAsBase64String),
AuthenticationCertificatePassword);
}
return null;
}
Error:
{System.Security.Cryptography.CryptographicException: The specified network password is not correct.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password)
at CryptoPlay.Program.AuthenticationCertificate(String AuthenticationCertificateAsBase64String, String AuthenticationCertificatePassword) in d:\personal\CryptoPlay\CryptoPlay\Program.cs:line 154
at CryptoPlay.Program.Main(String[] args) in d:\personal\CryptoPlay\CryptoPlay\Program.cs:line 59
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()}
The error indicates towards the password being not correct but that is not true. If someone is interested, here is the full code for reference (replacing the filenames and passwords to generic names as example)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
namespace CryptoPlay
{
class Program
{
static void Main(string[] args)
{
X509Certificate2 spCert = GetCertificateForUse();
X509Certificate2 encryptCert = GetCertificateUsedForEncryption();
string AuthenticationCertificatePasswordBase64String = EncryptAsBase64String(encryptCert, "Password1!");
Console.WriteLine("AuthenticationCertificatePasswordBase64String:");
Console.WriteLine(AuthenticationCertificatePasswordBase64String);
string AuthenticationCertificatePassword = DecryptFromBase64String(AuthenticationCertificatePasswordBase64String);
Console.WriteLine("AuthenticationCertificatePassword:");
Console.WriteLine(AuthenticationCertificatePassword);
string CertificateAsBase64String = EncryptAsBase64String(encryptCert, spCert);
Console.WriteLine("CertificateAsBase64String");
Console.WriteLine(CertificateAsBase64String);
byte[] rawdata = DecryptBytesFromBase64String(CertificateAsBase64String);
Console.WriteLine("Raw data: " + PrintBytes(rawdata));
string AuthenticationCertificateAsBase64String = Convert.ToBase64String(DecryptBytesFromBase64String(CertificateAsBase64String));
Console.WriteLine("AuthenticationCertificateAsBase64String:");
Console.WriteLine(AuthenticationCertificateAsBase64String);
byte[] rawdata2 = Convert.FromBase64String(AuthenticationCertificateAsBase64String);
Console.WriteLine("Raw data: " + PrintBytes(rawdata2));
if (ByteArrayCompare(rawdata, rawdata2))
Console.WriteLine("Raw data are same");
X509Certificate2 certFromConfig = AuthenticationCertificate(AuthenticationCertificateAsBase64String, AuthenticationCertificatePassword);
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static byte[] DecryptBytesFromBase64String(string payloadBase64String, X509Certificate2 decryptingCert = null)
{
try
{
var env = new EnvelopedCms();
env.Decode(Convert.FromBase64String(payloadBase64String));
if (decryptingCert != null)
{
env.Decrypt(new X509Certificate2Collection(decryptingCert));
}
else
{
env.Decrypt();
}
return env.ContentInfo.Content;
}
catch (Exception e)
{
throw new CryptographicException("Failed to decrypt: " + payloadBase64String, e);
}
}
public static string DecryptFromBase64String(string payloadBase64String, X509Certificate2 decryptingCert = null)
{
return Encoding.UTF8.GetString(DecryptBytesFromBase64String(payloadBase64String, decryptingCert));
}
public static string EncryptAsBase64String(X509Certificate2 cert, string payload)
{
return EncryptAsBase64String(cert, Encoding.UTF8.GetBytes(payload));
}
public static string EncryptAsBase64String(X509Certificate2 cert, byte[] payload)
{
var ci = new ContentInfo(payload);
var env = new EnvelopedCms(ci);
env.Encrypt(new CmsRecipient(cert));
return Convert.ToBase64String(env.Encode());
}
public static string EncryptAsBase64String(X509Certificate2 encryptingCert, X509Certificate2 payload)
{
byte[] bytes = payload.Export(X509ContentType.Pfx);
return EncryptAsBase64String(encryptingCert, bytes);
}
private static X509Certificate2 GetCertificateUsedForEncryption()
{
string certPath = "D:\\encryptcert.pfx";
string certPassword = "P@ssword123";
var cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.Exportable);
return cert;
}
private static X509Certificate2 GetCertificateForUse()
{
string certPath = "D:\\securecert.pfx";
string certPassword = "Password1!";
var cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.Exportable);
return cert;
}
public static X509Certificate2 AuthenticationCertificate(string AuthenticationCertificateAsBase64String, string AuthenticationCertificatePassword)
{
if (!string.IsNullOrEmpty(AuthenticationCertificateAsBase64String) &&
AuthenticationCertificatePassword != null)
{
Console.WriteLine("AuthenticationCertificateAsBase64String: " + AuthenticationCertificateAsBase64String);
Console.WriteLine("AuthenticationCertificatePassword: " + AuthenticationCertificatePassword);
return new X509Certificate2(Convert.FromBase64String(AuthenticationCertificateAsBase64String),
AuthenticationCertificatePassword);
}
return null;
}
public static string PrintBytes(byte[] byteArray)
{
var sb = new StringBuilder("new byte[] { ");
for (var i = 0; i < byteArray.Length; i++)
{
var b = byteArray[i];
sb.Append(b);
if (i < byteArray.Length - 1)
{
sb.Append(", ");
}
}
sb.Append(" }");
return sb.ToString();
}
static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
if (a1[i] != a2[i])
return false;
return true;
}
}
}
Upvotes: 0
Views: 2581
Reputation: 33088
Your initial question is about the overloads which take a string
as the first parameter, but your code uses the ones that use byte[]
.
The easy answer is that the string one is just a filename to load as a byte array and then call the other one (it's a bit more nuanced than that, e.g. the file one doesn't like symbolic links).
The following types are known (by me) to work:
-----BEGIN CERTIFICATE-----\n[etc]\n-----END CERTIFICATE-----
)-----BEGIN PKCS7-----\n...
) (uses the embedded certificate identified by the first signer)Whether or not you pass in a password has no bearing on what file format the blob gets identified as. Unless your profile or temp directory is on a SMB/CIFS share, Windows reporting ERROR_BAD_PASSWORD
means it thinks your bytes represented a PFX, but that the PFX MAC could not be validated using the input password as the key. I'd recommend checking your password variable for embedded newline or linefeed characters (or nulls); or leading or trailing spaces.
Upvotes: 2