Защищенные данные.Незащищенному методу не удается расшифровать

#.net #powershell #cruisecontrol.net #dpapi

#.net #powershell #cruisecontrol.net #dpapi

Вопрос:

У нас есть процесс сборки, которому необходимо расшифровать пароль, который он затем использует для подключения к базе данных. Мы используем 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:DOMAINBUILDUSER powershell.exe
  

Затем я запускаю скрипт PowerShell для снятия защиты / расшифровки пароля и получаю ту же ошибку.

Я использовал Process Monitor для отслеживания любых сбоев или событий отказа в доступе, и их не было.

Я могу расшифровать пароль при входе в систему с моей собственной учетной записью домена.

Что происходит? Профиль моего пользователя сборки не загружается? Есть ли где-нибудь какой-нибудь параметр безопасности, о котором я не знаю, чтобы включить это? Почему я не могу расшифровать пароль?

Ответ №1:

Ошибка разработчика. Оказывается, я шифровал в области CurrentUser, а не в области LocalMachine. Я обновил свой скрипт, и теперь все работает.

Ответ №2:

Вы обращаете внимание на то, как вы кодируете зашифрованный 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:Temppass.txt -Value ([Convert]::ToBase64String($bakCryptedPWD_ByteArray))
  

Вернуться к строке, использующей регистр символов ANSI (в пароле могут быть специальные символы)

 Clear-Host

Add-Type -assembly System.Security

$resCryptedPWD_ByteArray = [Convert]::FromBase64String((Get-Content -LiteralPath c:Temppass.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)
  

Комментарии:

1. Проблема не в этом. Вы получаете ошибку, отличную от моей, если передаете массив байтов, которые не могут быть расшифрованы.