PowerShell: Coverting Hex or Bytes Array to ASCII

The following is an illustration of a practical usage of decrypting an ASCII encoded value from a CRM database. This is also a solution for the issue of “Recovering ‘lost’ CRM encryption key.” May the power of Google helps someone who is facing such problems.

# getCrmEncryptionPassword.ps1

$orgName='TESTORG'
$sqlServer='SQLSERVER'
$saUsername='sa'
$saPassword='password'
$saCredential=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $saUsername,$(ConvertTo-securestring $saPassword -AsPlainText -Force)

function getSymmetricKey($orgName){
    $moduleName='sqlps'    
    if(!(Get-Module -ListAvailable -Name $moduleName -ea SilentlyContinue)){
        if(!('NuGet' -in (get-packageprovider).Name)){    
            try{
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction SilentlyContinue;
                }
            catch{
                #Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
                #Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction SilentlyContinue;
                }            
            }
        Install-Module -Name $moduleName -Force -Confirm:$false
        }
    import-module $moduleName  
    $querySymmetricKey=@"
        USE MSCRM_CONFIG
        SELECT VarBinaryColumn FROM OrganizationProperties
        WHERE (ColumnName = 'SymmetricKeySource')
        AND Id IN (SELECT Id FROM Organization WHERE UniqueName = '$orgName')
"@
    $symmetricKey=invoke-sqlcmd $querySymmetricKey
    return $symmetricKey.VarBinaryColumn
}

$encodedBytes=Invoke-Command -ComputerName $sqlServer -Credential $saCredential -ScriptBlock{
                param($getSymmetricKey,$orgName)
                write-host "Executing function on $env:computername"
                Write-Host "$getSymmetricKey"
                pause
                [ScriptBlock]::Create($getSymmetricKey).invoke($orgName)
                } -Args ${function:getSymmetricKey},$orgName

function convertEncodedBytesToString($bytesArray,$encoding='default'){
    # Convert encoded bytes => decimal string => decimal bytes array => string
    #source: https://docs.microsoft.com/en-us/dotnet/api/system.bitconverter.tochar?view=netcore-3.1
    $ErrorActionPreference='stop'
    try{
        $decimalString=[System.Text.Encoding]::default.GetChars($bytesArray) -join ''
        $decimalBytes=$decimalString.Split(':')
        $result=$(for ($i=0;$i -lt $decimalBytes.count;$i+=2){[System.BitConverter]::ToChar($decimalBytes,$i)}) -join ''
        return $result
    }catch{
        Write-Error $_
        return $false
        }
}

convertEncodedBytesToString $encodedBytes
# Other Miscellaneous conversions

function convertHexToAscii($hexValue){
    try{
        $initChars=$hexValue.ToString().Substring(0,2)
        $startIndex=if($initChars -eq '0x'){2}else{0}
        $keys=$hexValue -split '-'
        $decimalBytes = $(for($i=$startIndex; $i -lt $keys.length; $i+=2){[char][int]::Parse($keys.substring($i,2),'HexNumber')}) -join ''
        $decimalArray=$decimalBytes.Split(':')
        $ascii=$(for ($i=0;$i -lt $decimalArray.count;$i+=2){[CHAR][BYTE]$decimalArray[$i]}) -join ''
        return $ascii
    }catch{
        Write-Warning "Please validate the input by checking this error:`r`n$($Error[0].Exception.Message)"
        }
}

function convertBytesArrayToAscii($bytesArray){
    function convertDecimalBytesToAscii($decimalBytes){    
        $decimalArray=$decimalBytes.Split(':')
        $ascii=$(for ($i=0;$i -lt $decimalArray.count;$i+=2){[CHAR][BYTE]$decimalArray[$i]}) -join ''
        return $ascii
        }

    function convertBytesArrayToDecimalBytes($bytesArray){
        return [System.Text.Encoding]::ASCII.GetString($bytesArray)
        }
    try{
        $decimalBytes=convertBytesArrayToDecimalBytes $bytesArray
        $ascii=convertDecimalBytesToAscii $decimalBytes
        return $ascii
        }
    catch{
        write-warning $error[0].Exception.Message
        }
}

# How to convert Bytes Array => Hex
$hexValue=[System.BitConverter]::ToString($bytesArray)

# How to convert decimalBytes => ASCII
$decimalBytes=($hexValue.split('-') | % {[char][byte]"0x$_"}) -join ''

# How to convert bytes => binary
[system.Text.Encoding]::Default.GetBytes($bytesArray) | %{[System.Convert]::ToString($_,2).PadLeft(8,'0') }

# Enable UTF8 encoding in PShell session
$OutputEncoding=[console]::InputEncoding=[console]::OutputEncoding=New-Object System.Text.UTF8Encoding

# Convert text => bytes
$text='hello world!'
$bytes = [System.Text.Encoding]::UTF8.GetBytes($text)

# How to convert bytes => text
[System.Text.Encoding]::UTF8.GetChars($bytes) -join ''

Leave a Reply

Your email address will not be published. Required fields are marked *