如何让C#控制台程序向PowerShell返回SecureString或加密字符串
C#实现SecureString转PowerShell兼容的加密字符串
要解决PowerShell日志记录明文密码的问题,核心是在C#里直接生成和ConvertFrom-SecureString格式一致的加密字符串,绕开PowerShell的明文转换环节。下面是具体实现方案:
核心逻辑
PowerShell的ConvertFrom-SecureString默认用**DPAPI(数据保护API)**加密,C#里可以直接调用同API实现兼容:
- 接收控制台输入并转为
SecureString(避免明文在内存留存) - 将
SecureString转字节数组(用完立即清零) - 用DPAPI加密字节数组,转Base64字符串得到最终加密结果
完整代码示例
using System; using System.Security; using System.Security.Cryptography; using System.Text; class SecureStringConverter { static void Main(string[] args) { Console.Write("输入需加密的内容:"); SecureString inputSecureStr = ReadHiddenInput(); string encryptedResult = ConvertToPowerShellCompatibleString(inputSecureStr); Console.WriteLine("\n生成的加密字符串:"); Console.WriteLine(encryptedResult); inputSecureStr.Dispose(); } // 读取隐藏的控制台输入,直接返回SecureString static SecureString ReadHiddenInput() { SecureString secureInput = new SecureString(); ConsoleKeyInfo key; do { key = Console.ReadKey(true); // 处理退格键 if (key.Key == ConsoleKey.Backspace && secureInput.Length > 0) { secureInput.RemoveAt(secureInput.Length - 1); Console.Write("\b \b"); } // 处理普通输入字符 else if (key.Key != ConsoleKey.Enter && key.Key != ConsoleKey.Backspace) { secureInput.AppendChar(key.KeyChar); Console.Write("*"); } } while (key.Key != ConsoleKey.Enter); return secureInput; } // 将SecureString转为PowerShell兼容的加密字符串 static string ConvertToPowerShellCompatibleString(SecureString secureStr) { IntPtr unmanagedPtr = IntPtr.Zero; byte[] plainBytes = null; byte[] encryptedBytes = null; try { // 把SecureString转成非托管字符串 unmanagedPtr = System.Runtime.InteropServices.Marshal.SecureStringToGlobalAllocUnicode(secureStr); int byteLength = secureStr.Length * 2; // Unicode字符占2字节 plainBytes = new byte[byteLength]; System.Runtime.InteropServices.Marshal.Copy(unmanagedPtr, plainBytes, 0, byteLength); // 用DPAPI加密(当前用户上下文,和PowerShell默认一致) encryptedBytes = ProtectedData.Protect(plainBytes, null, DataProtectionScope.CurrentUser); // 转Base64字符串输出 return Convert.ToBase64String(encryptedBytes); } finally { // 清理非托管内存 if (unmanagedPtr != IntPtr.Zero) { System.Runtime.InteropServices.Marshal.ZeroFreeGlobalAllocUnicode(unmanagedPtr); } // 清零字节数组,避免明文残留 if (plainBytes != null) Array.Clear(plainBytes, 0, plainBytes.Length); if (encryptedBytes != null) Array.Clear(encryptedBytes, 0, encryptedBytes.Length); } } }
验证方式
把生成的加密字符串复制到PowerShell,用以下命令解密验证:
$encryptedStr = "你的加密字符串" $secureStr = ConvertTo-SecureString $encryptedStr $plainText = [System.Net.NetworkCredential]::new("", $secureStr).Password Write-Host $plainText
注意点
- 加密结果仅在当前用户、同一台机器下可解密;如果需要跨机器,要改用密钥加密(对应PowerShell的
ConvertFrom-SecureString -Key),C#里需手动实现AES加密逻辑。 - 代码中严格清理了所有明文相关内存,降低泄露风险。
内容的提问来源于stack exchange,提问作者Rick Childers
相关产品推荐
相关产品推荐

