代码之家  ›  专栏  ›  技术社区  ›  Mike Bruno

访问模拟帐户的私钥

  •  1
  • Mike Bruno  · 技术社区  · 7 年前

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

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

    系统安全加密。CryptographicException:系统在system.Security.Cryptology.X509Certificates.X509 Certification2.get\u PrivateKey()中找不到指定的文件

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

    1 回复  |  直到 7 年前
        1
  •  1
  •   Anders    7 年前

    您需要根据 CreateProcessAsUser 文档:

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

    你可以试着打电话 LoadUserProfile 之后 LogonUser