You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让C#控制台程序向PowerShell返回SecureString或加密字符串

C#实现SecureString转PowerShell兼容的加密字符串

要解决PowerShell日志记录明文密码的问题,核心是在C#里直接生成和ConvertFrom-SecureString格式一致的加密字符串,绕开PowerShell的明文转换环节。下面是具体实现方案:

核心逻辑

PowerShell的ConvertFrom-SecureString默认用**DPAPI(数据保护API)**加密,C#里可以直接调用同API实现兼容:

  1. 接收控制台输入并转为SecureString(避免明文在内存留存)
  2. 将SecureString转字节数组(用完立即清零)
  3. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:55:18