2015-11-23 4 views
0

У меня есть зашифрованная стандартная строка, созданная в powershell через «convertfrom-securestring» и сохраняемая в файл. Позже я прочитал эту зашифрованную строку с помощью приложения C# (под тем же идентификатором пользователя и на том же компьютере). Я хочу преобразовать эту зашифрованную строку в объект securestring. В powershell можно сделать это, используя «convertto-securestring». Как можно это сделать безопасно в C#?безопасно преобразовать зашифрованную стандартную строку в securestring

Мне известно об этом ответе (How can I use ConvertTo-SecureString), , но предполагается, что зашифрованная строка была создана с помощью известного ключа. Это отличается от случая, когда зашифрованная строка была создана без ключа (и, таким образом, привязана к идентификатору пользователя и машине, на которой она была создана.)

Обратите также внимание на то, что в комментариях по вышеуказанному вопросу, была указана документация от Microsoft, в которой указано, что API защиты данных Windows (DPAPI) используется в случае отсутствия ключа. В этой статье (https://msdn.microsoft.com/en-us/library/ms229741(v=vs.110).aspx) показано, как использовать DPAPI, но, к сожалению, использование этого метода, как указано в статье Microsoft, приведет к тому, что строка будет иметь четкий текст в строковом объекте (над которым мы не имеем никакого контроля, a-vis), и поэтому использование его в указанном порядке будет небезопасным.

Фактически, это фактически комбинация этого (How to decrypt a string in C# which is encrypted via PowerShell) и вопроса в How can I use ConvertTo-SecureString.

Для записи, этот код работает, но я не уверен, что проблемы могут быть с хранением расшифрованные строки в массиве байт, даже если я колошматить его как можно быстрее:

public static unsafe 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), NumberStyles.HexNumber, CultureInfo.InvariantCulture); 
    } 

    byte[] decrypted = ProtectedData.Unprotect(encrypted, (byte[])null, DataProtectionScope.CurrentUser); 
    lngth = decrypted.Length - 1; 
    byte[] chr = new byte[2]; 
    SecureString secureString = new SecureString(); 
    for (int i = 0; i < lngth;) 
    { 
     chr[0] = decrypted[i]; decrypted[i++] = 0; 
     chr[1] = decrypted[i]; decrypted[i++] = 0; 
     string passwd = UnicodeEncoding.Unicode.GetString(chr); 
     secureString.AppendChar(passwd[0]); 
    } 

    return secureString; 
} 

Обратите внимание на кажущуюся глупость копирования байтовых пар от decrypted до chr, а затем с применением UnicodeEncoding.Unicode.GetString по одному символу за раз. Если бы мы просто сделать это

string passwd = UnicodeEncoding.Unicode.GetString(decrypted); 
for (int i = 0; i < passwd.Length; ++i) 
{ 
    secureString.AppendChar(passwd[i]); 
} 

тогда мы разместили «расшифрованы» строку в объект строки, и он может торчать в памяти - мы не имеем никакого контроля. Вышеприведенный код избегает этого. Мне непонятно, что оставить массив байтов и обнулить его там гарантирует, что в памяти не будет никаких копий. Может кто-нибудь прокомментировать это?

+0

Возможный дубликат [Как использовать ConvertTo-SecureString] (http://stackoverflow.com/questions/13633826/how-can-i-use-convertto-securestring) –

+0

Насколько безопасна SecureString? Он защищает (расшифровывает) буфер с каждым вызовом AppendChar() или вызовом InsertAt() или SetAt(), и выполняет работу, и снова зашифровывает буфер. Блок памяти будет содержать незашифрованные данные в течение очень короткого времени. Я думаю, что это то, что вы также должны реализовать; хранить незашифрованные данные в памяти как можно короче. –

+0

Да, отдельные байты будут отображаться мгновенно в ясном тексте один за другим. Но проблема заключается в следующем: при использовании одного символа для хранения символов этот одиночный символ не является чем-то вроде кучи, где нужно беспокоиться о его жизни после смерти, т. Е. О том, что он висит вокруг в памяти кучи. Во-вторых, мы помещаем что-то вроде пароля в строку, в C# мы теряем контроль над памятью, содержащей эту строку: у нас нет способа гарантировать уничтожение (переписывание) строки байта. Он может долгое время находиться в памяти и находить его в спящих изображениях и т. Д. –

ответ

0

Я не знаю, есть ли способ C# для этого, но если нет, вы всегда можете вернуться к использованию рабочей области для выполнения конвейера powershell и просто использовать командлет.

Если вы сохраните пробел открытым, повторные казни будут довольно быстрыми.