1

我有一个加密的标准字符串,通过“convertfrom-securestring”在powershell中创建并保存到文件中。后来,我用 C# 应用程序(在同一用户 ID 和同一台机器上)读取了这个加密字符串。我想将此加密字符串转换为安全字符串对象。在 powershell 中,可以使用“convertto-securestring”来做到这一点。如何在 c# 中安全地做到这一点?

我知道这个答案(How can I use ConvertTo-SecureString),但它假设加密字符串是使用已知密钥创建的。这与在没有密钥的情况下创建加密字符串的情况不同(因此与构建它的用户 ID 和机器相关联。)

另请注意,在上述问题的评论中,引用了 Microsoft 的文档,表明在未提供密钥的情况下使用 Windows 数据保护 API (DPAPI)。这篇文章 ( https://msdn.microsoft.com/en-us/library/ms229741(v=vs.110).aspx ) 展示了如何使用 DPAPI,但不幸的是,以 Microsoft 文章中指定的方式使用它会result 再次导致字符串在字符串对象中以明文形式出现(我们无法控制,相对于处置),因此以指示的方式使用它是不安全的。

实际上,这实际上是这个(如何在 C# 中解密通过 PowerShell 加密的字符串)和如何使用 ConvertTo-SecureString中的问题的组合。

作为记录,这段代码有效,但我不确定将解密的字符串存储在字节和字符数组中可能会出现什么问题,即使我尽可能快地破坏它:

public static System.Security.SecureString MakeSecurityString(string pwd)
{
    int lngth = pwd.Length / 2;
    byte[] encrypted = new byte[lngth];
    for (int i = 0; i < lngth; ++i)
    {
        encrypted[i] = byte.Parse(pwd.Substring(2 * i, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture);
    }

    byte[] decrypted = System.Security.Cryptography.ProtectedData.Unprotect(encrypted, (byte[])null, System.Security.Cryptography.DataProtectionScope.CurrentUser);
    var chars = System.Text.UnicodeEncoding.Unicode.GetChars(decrypted);
    for(int i=0; i<decrypted.Length; ++i)
    {
        decrypted[i]=0;
    }
    var secureString = new System.Security.SecureString();
    for (int i = 0; i < chars.Length; ++i)
    {
        secureString.AppendChar(chars[i]);
        chars[i] = '\0';
    }

    return secureString;
}

decrypted我认为上面的代码是安全的,除了密码在 byte-array然后是 char-array中以明文形式出现的短暂时刻chars,尽管我们尽快将它们归零,以便至少密码不能徘徊退出例程后在内存中。我们secureString.AppendChar多次调用,正如 Oguz Ozgu 在下面指出的那样,这意味着secureString必须在内部解密然后重新加密字符串——人们会认为这是安全地完成的。有人可以评论上述代码的安全问题吗?

编辑:请注意,下面的代码将避免多次调用secureString.AppendChar,但它必须作为“不安全”运行:

        SecureString secureString;
        fixed (char* pChars = chars)
        {
            secureString = new SecureString(pChars, chars.Length);
        }
        for (int i = 0; i < chars.Length; ++i)
        {
            chars[i] = '\0';
        }
        return secureString;

另请注意,下面 Indigo 评论中的链接清楚地表明,这仅在 WINDOWS 上的 .NET 框架中是安全的。

4

1 回答 1

0

我不知道是否有本地 C# 方法可以执行此操作,但如果没有,您始终可以退回到使用运行空间来执行 powershell 管道并仅使用 cmdlet。

如果您保持运行空间打开,重复执行将非常快。

于 2015-11-23T21:13:20.293 回答