I was beginning to explore the DPAPI and my very first sample code does not work. What I expected was for my byte array to change after a call to [ProtectedMemory]::Protect()
. However, the byte array was exactly the same before and after the call. So either there is something I don't understand about Powershell (likely) OR there is something I don't understand about using the DPAPI (likely), OR the DPAPI is a scam that does not actually encrypt anything (unlikely). Here is my sample code:
using namespace System.Security.Cryptography
using namespace System.Text
function Protect-String {
param (
[Parameter(ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
[string]$Secret
)
begin {
Add-Type -AssemblyName System.Security
}
process {
$bytes = [UnicodeEncoding]::UTF8.GetBytes($secret)
$padding = [byte[]]::new(16 - $bytes.length % 16)
$bytes += $padding
Write-host "Original: $bytes"
$Scope = [MemoryProtectionScope]::SameLogon
[ProtectedMemory]::Protect($bytes, $Scope)
Write-host "After : $bytes"
}
}
output:
PS C:\> Protect-String something
Original: 115 111 109 101 116 104 105 110 103 0 0 0 0 0 0 0
After : 115 111 109 101 116 104 105 110 103 0 0 0 0 0 0 0
What I know so far:
This code is for Powershell 5 under .Net and will not work with Powershell 7 under .Net Core as the System.Security.Cryptography
namespace does not contain the DPAPI classes - these rely upon Windows OS features.
The Protect
should encrypt the byte array in place. Since my input and output are the same, I wonder if PowerShell is passing a copy/clone of the byte[]
?