我正在开发一个程序,用于冒充其他帐户,然后使用模拟帐户密钥库中的私钥解密文件。
问题是虽然我能够打开模拟帐户的证书存储并使用适当的证书实例化X509Certificate2对象,但当程序尝试访问私钥时,我收到一个例外:
System.Security.Cryptography.CryptographicException:系统找不到指定的文件...在System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
我能够使用FindPrivateKey.exe实用程序&找到模拟用户在文件系统中的私钥。发现它位于C:\ Users \ TESTUSR \ AppData \ Roaming \ Microsoft \ Crypto \ RSA ...我使用this article作为指南,以确保我自己的帐户可以访问私钥文件。我绝对可以从NTFS角度访问密钥文件,因为我可以在记事本中加载它(虽然它显然是jiberish)。
很偶然,我发现如果我使用runas预加载模拟帐户的本地配置文件,程序 可以工作,例如,以该用户打开命令提示符。
非常感谢任何建议!
class Program
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
static void Main(string[] args)
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
SafeTokenHandle safeTokenHandle;
try
{
string username = "TESTUSR";
string domain = "CONTOSO";
string password = "P@ssw0rd";
// Call LogonUser to obtain a handle to an access token.
if (!LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
return;
if (safeTokenHandle == null)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
using (safeTokenHandle)
{
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
string neededCertSN = "17396B080000000000A5";
X509Store my = new X509Store(StoreLocation.CurrentUser);
my.Open(OpenFlags.ReadOnly);
string result;
foreach (X509Certificate2 cert in my.Certificates)
{
if (Regex.IsMatch(neededCertSN, cert.SerialNumber))
{
result = DecryptFile(args[0], ".txt", (RSACryptoServiceProvider)cert.PrivateKey);
Console.WriteLine("Result:\r\n" + result);
return;
}
}
Console.WriteLine("Encryption certificate not found.");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("An exception occurred:\r\n" + ex.ToString());
}
}
static string DecryptFile(string cypherTextFile, string plainTextFileExtension, RSACryptoServiceProvider rsaPrivateKey)
{
string plainTextFile = string.Empty;
try
{
if (!File.Exists(cypherTextFile))
return "Cyphertext file not found";
// Create instance of AesManaged for
// symetric decryption of the data.
using (AesManaged aesManaged = new AesManaged())
{
aesManaged.KeySize = 256;
aesManaged.BlockSize = 128;
aesManaged.Mode = CipherMode.CBC;
// Create byte arrays to get the length of
// the encrypted key and IV.
// These values were stored as 4 bytes each
// at the beginning of the encrypted package.
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
// Consruct the file name for the decrypted file.
if (plainTextFileExtension[0] != '.')
plainTextFileExtension = "." + plainTextFileExtension;
string[] parts = cypherTextFile.Split('.');
for (int x = 0; x < parts.Length - 1; x++)
plainTextFile = plainTextFile + parts[x];
plainTextFile = plainTextFile + plainTextFileExtension;
// Use FileStream objects to read the encrypted
// file (inFs) and save the decrypted file (outFs).
using (FileStream inFs = new FileStream(cypherTextFile, FileMode.Open))
{
inFs.Seek(0, SeekOrigin.Begin);
inFs.Seek(0, SeekOrigin.Begin);
inFs.Read(LenK, 0, 3);
inFs.Seek(4, SeekOrigin.Begin);
inFs.Read(LenIV, 0, 3);
// Convert the lengths to integer values.
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
// Determine the start postition of
// the ciphter text (startC)
// and its length(lenC).
int startC = lenK + lenIV + 8;
int lenC = (int)inFs.Length - startC;
// Create the byte arrays for
// the encrypted AesManaged key,
// the IV, and the cipher text.
byte[] KeyEncrypted = new byte[lenK];
byte[] IV = new byte[lenIV];
// Extract the key and IV
// starting from index 8
// after the length values.
inFs.Seek(8, SeekOrigin.Begin);
inFs.Read(KeyEncrypted, 0, lenK);
inFs.Seek(8 + lenK, SeekOrigin.Begin);
inFs.Read(IV, 0, lenIV);
// Use RSACryptoServiceProvider
// to decrypt the AesManaged key.
byte[] KeyDecrypted = rsaPrivateKey.Decrypt(KeyEncrypted, false);
// Decrypt the key.
using (ICryptoTransform transform = aesManaged.CreateDecryptor(KeyDecrypted, IV))
{
// Decrypt the cipher text from
// from the FileSteam of the encrypted
// file (inFs) into the FileStream
// for the decrypted file (outFs).
using (FileStream outFs = new FileStream(plainTextFile, FileMode.Create))
{
int count = 0;
int offset = 0;
int blockSizeBytes = aesManaged.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
// By decrypting a chunk a time,
// you can save memory and
// accommodate large files.
// Start at the beginning
// of the cipher text.
inFs.Seek(startC, SeekOrigin.Begin);
using (CryptoStream outStreamDecrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamDecrypted.Write(data, 0, count);
}
while (count > 0);
outStreamDecrypted.FlushFinalBlock();
outStreamDecrypted.Close();
}
outFs.Close();
}
inFs.Close();
}
}
}
return plainTextFile;
}
catch (Exception e)
{
return "An exception occurred:\r\n" + e.ToString();
}
}
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
我遇到的问题是,虽然我可以打开模拟帐户的证书存储区&amp;在X509Certificate2对象中获取正确的证书,当程序尝试使用私钥时,它是
答案 0 :(得分:1)
您需要根据CreateProcessAsUser
文档手动加载用户注册表:
CreateProcessAsUser不会将指定用户的配置文件加载到HKEY_USERS注册表项中。因此,要访问HKEY_CURRENT_USER注册表项中的信息,必须在调用CreateProcessAsUser之前使用LoadUserProfile函数将用户的配置文件信息加载到HKEY_USERS中。
RunAs不会在您的进程中更改HKEY_CURRENT_USER,但会导致在HKEY_USERS下加载配置单元。
您可以在LoadUserProfile
...
LogonUser