question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can not decrypt correctly in PowerShell 7.0.3 in CloudShell and Linux

See original GitHub issue

Steps to reproduce


PS /home/xiaogang> [int]$timeInt = $(Get-Date -UFormat '%s')
PS /home/xiaogang> $passwd = "bl0ckCh@!n$timeInt)" | ConvertTo-SecureString -AsPlainText -Force
PS /home/xiaogang> $psTxt = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($passwd))
PS /home/xiaogang> $psTxt
b

Expected behavior

PS C:\Users\xidi> [int]$timeInt = $(Get-Date -UFormat '%s')
PS C:\Users\xidi> $passwd = 'bl0ckCh@!n$timeInt)' | ConvertTo-SecureString -AsPlainText -Force
PS C:\Users\xidi> $psTxt = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($passwd))
PS C:\Users\xidi> $psTxt
bl0ckCh@!n$timeInt)

Actual behavior

b is return instead of bl0ckCh@!n$timeInt)

Environment data

Issue only happens in PowerShell 7.0.3 in CloudShell and Ubuntu 18.04, But in PowerShell 7.0.3, 7.0.0, 6.2.4 and Windows PowerShell in my local Windows machine, it is OK.


Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
jborean93commented, Aug 21, 2020

Thanks to @SeeminglyScience I now know what the difference between SecureStringToBSTR and SecureStringToGlobalAllocUnicode is. The former encodes the length of the string in 4 bytes just before the pointer. This is important if your string contains a null character as any of the other methods would see that as the end of the string.

$pass = "pass`0word" | ConvertTo-SecureString -AsPlainText -Force
$pass | ConvertFrom-SecureString
# 7000610073007300000077006f0072006400

$bstrPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass)
$bstrBytes = [byte[]]::new(24)
[System.Runtime.InteropServices.Marshal]::Copy([IntPtr]::Add($bstrPtr, -4), $bstrBytes, 0, $bstrBytes.Length)

$bstrBytes | Format-Hex

#    Label: Byte (System.Byte) <630BBC81>
#
#           Offset Bytes                                           Ascii
#                  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
#           ------ ----------------------------------------------- -----
# 0000000000000000 12 00 00 00 70 00 61 00 73 00 73 00 00 00 77 00 �   p a s s   w 
# 0000000000000010 6F 00 72 00 64 00 00 00                         o r d   

$plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstrPtr)
$plaintext.Length
# 9

$plaintext
# password

$uniPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($pass)
$uniBytes = [byte[]]::new(24)
[System.Runtime.InteropServices.Marshal]::Copy([IntPtr]::Add($uniPtr, -4), $uniBytes, 0, $uniBytes.Length)

$uniBytes | Format-Hex

#    Label: Byte (System.Byte) <4552DC2C>
#
#           Offset Bytes                                           Ascii
#                  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
#           ------ ----------------------------------------------- -----
# 0000000000000000 00 00 00 00 70 00 61 00 73 00 73 00 00 00 77 00     p a s s   w 
# 0000000000000010 6F 00 72 00 64 00 00 00                         o r d   

$plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($uniPtr)
$plaintext.Length
# 4

$plaintext
# pass

It also turns out that the GetNetworkCredential() method also fails when dealing with null bytes in the string so I would take back my recommendation, even for such a rare edge case. Ultimately you should be using SecureStringToBSTR and PtrToStringBSTR like so

$pass = "pass`0word" | ConvertTo-SecureString -AsPlainText -Force

$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass)
try {
    $plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
} finally {
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
2reactions
mklement0commented, Aug 21, 2020

Good info here, but this has indeed come up several times. Here’s the previous list of issues: https://github.com/PowerShell/PowerShell/issues?q=is%3Aissue+ptrtostringauto+is%3Aclosed+NOT+%2Fhome%2Fchythu%2Ftemp

<div> GitHub</div><div>PowerShell/PowerShell</div><div>PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.</div>
Read more comments on GitHub >

github_iconTop Results From Across the Web

Troubleshooting AWS CloudShell
Solution: Install an updated version of Edge browser from the Microsoft site . (back to top). Arrow keys not working correctly in PowerShell....
Read more >
PowerShell differences on non-Windows platforms
This article summarizes the differences between PowerShell on Windows and PowerShell on non-Windows platforms.
Read more >
Cannot Encrypt/Decrypt String in Powershell
I am trying to encrypt & decrypt a string with ConvertTo-SecureString , output the string plaintext, and verify that the key works correctly...
Read more >
Powershell doesn't find certain files
But in Powershell (version 7.0.3) certain .lnk files (which I do have on my $env:PATHEXT ) fail with a ResourceUnavailable: Program '[name]' ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found