访问模拟帐户的私钥

我正在开发一个旨在模拟另一个帐户的程序,然后使用来自模拟帐户密钥库的私钥解密文件。

问题是,虽然我能够打开模拟帐户的证书存储并使用适当的证书实例化X509Certificate2对象,但是当程序试图访问私钥时,我收到一个exception:

System.Security.Cryptography.CryptographicException:系统找不到指定的文件…在System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()

我能够find模拟用户的私钥在文件系统中使用FindPrivateKey.exe实用工具,并发现它位于C:\ Users \ TESTUSR \ AppData \ Roaming \ Microsoft \ Crypto \ RSA …我用这篇文章作为指导,以确保我自己的帐户有权访问私钥文件。 我确实可以从NTFS的angular度访​​问密钥文件,因为我可以在记事本中加载它(虽然显然是jiberish)。

很偶然的是,我发现如果我通过使用runas预先加载模拟帐户的本地configuration文件,那么该程序就可以工作,例如,以该用户的身份打开命令提示符。

任何build议将不胜感激!

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); } } 

我遇到的问题是,虽然我可以打开模拟帐户的证书存储并获取X509Certificate2对象中正确的证书,当程序尝试使用私钥时,它

您需要根据CreateProcessAsUser文档手动加载用户注册表:

CreateProcessAsUser不会将指定的用户的配置文件加载到HKEY_USERS注册表项。 因此,要访问HKEY_CURRENT_USER注册表项中的信息,您必须在调用CreateProcessAsUser之前用LoadUserProfile函数将用户的配置文件信息加载到HKEY_USERS。

RunAs不会在您的进程中更改HKEY_CURRENT_USER,但会导致配置单元在HKEY_USERS下加载。

您可以尝试在LogonUser之后调用LoadUserProfile