Метод ProtectedData.Unprotect не может расшифровать
У нас есть процесс сборки, который должен расшифровать пароль, который он затем использует для подключения к базе данных. Мы используем API защиты данных (DPAPI) для шифрования пароля в области компьютера на сервере сборки (я вошел в систему с моей собственной учетной записью домена) с помощью PowerShell:
[Security.Cryptography.ProtectedData]::Protect( $passwordBytes, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine );
Расшифровка также выполняется в сценарии PowerShell, который выполняется CruiseControl.NET и работает как наш пользователь сборки:
[Security.Cryptography.ProtectedData]::Unprotect( $encryptedbytes, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine );
Призыв к Unprotect
Однако возникает ошибка со следующим сообщением: "Ключ недействителен для использования в указанном состоянии.". Согласно документации, эта ошибка может возникать при использовании олицетворения, и олицетворяющий код должен загружать профиль пользователя.
В целях безопасности пользователю сборки запрещен вход через службы терминалов. Чтобы проверить проблему, я вошел на сервер сборки как сам, а затем использовал runas, чтобы открыть приглашение PowerShell от имени пользователя сборки:
runas /profile /user:DOMAIN\BUILDUSER powershell.exe
Затем я запускаю сценарий PowerShell для снятия защиты / дешифрования пароля и получаю ту же ошибку.
Я использовал Process Monitor для наблюдения за любыми сбоями или событиями, в которых отказано в доступе, а их не было.
Я могу расшифровать пароль при входе в свою учетную запись домена.
В чем дело? Мой пользовательский профиль сборки не загружается? Есть ли где-то настройки безопасности, о которых я не знаю, чтобы включить это? Почему я не могу расшифровать пароль?
2 ответа
Ошибка разработчика. Оказывается, я шифровал в области CurrentUser, а не в LocalMachine. Я обновил свой скрипт, и теперь все работает.
Обращаете ли вы внимание на то, как вы кодируете зашифрованный массив ByteArray в своем файле. Здесь ниже я извлекаю способ, которым я делаю это на одном из моих серверов для строки подключения (я заменяю здесь введенной строкой)
Конвертировать в Base64, чтобы поместить его в файл конфигурации
Clear-Host
Add-Type -assembly System.Security
$passwordASCII = Read-Host -Prompt "Enter Password"
$bakCryptedPWD_ByteArray = [System.Security.Cryptography.ProtectedData]::Protect( $passwordASCII.tochararray(), $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
Set-Content -LiteralPath c:\Temp\pass.txt -Value ([Convert]::ToBase64String($bakCryptedPWD_ByteArray))
Вернуться к строке с учетом символов ANSI (может иметь специальные символы в пароле)
Clear-Host
Add-Type -assembly System.Security
$resCryptedPWD_ByteArray = [Convert]::FromBase64String((Get-Content -LiteralPath c:\Temp\pass.txt))
$clearPWD_ByteArray = [System.Security.Cryptography.ProtectedData]::Unprotect( $resCryptedPWD_ByteArray, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
$enc = [system.text.encoding]::Default
$enc.GetString($clearPWD_ByteArray)