We've updated the ServiceNow Community Code of Conduct, adding guidelines around AI usage, professionalism, and content violations. Read more

How to Decrypt OpenSSL AES-256-CBC Secrets in ServiceNow via PowerShell

Ajay_saitej
Tera Contributor

Overview

When integrating ServiceNow with external security tools (like HashiCorp Vault, CyberArk, or custom DevOps pipelines), you often receive secrets encrypted via OpenSSL. Since ServiceNow's native JavaScript (Rhino) doesn't have a built-in library for OpenSSL's specific "Salted" key derivation, we have to bridge the gap using a PowerShell Step on a MID Server.

This article provides a reusable script to decrypt AES-256-CBC strings that use the EVP_BytesToKey (MD5) derivation.

The Challenge: The "Salted__" Format

Standard AES is just an algorithm, but OpenSSL adds a specific "envelope" to the data:

  1. It prefixes the data with the string Salted__.
  2. It follows that with 8 bytes of random Salt.
  3. It uses a specific loop (KDF) to turn your password into a 32-byte Key and a 16-byte IV.

The Solution: MID Server PowerShell Script

The following script can be used in a PowerShell Step within Flow Designer or as a MID Server Script File.

  1. The Script Logic

PowerShell

function Decrypt-AES {

    param(

        [string]$encryptedResponse, # The Base64 string from the external tool

        [string]$secret            # Your shared Master Key/Password

    )

    try {

        # 1. Convert Base64 and extract the Salt (Bytes 8-15)

        $encrypted = [Convert]::FromBase64String($encryptedResponse)

        $salt = $encrypted[8..15]

        $encryptedData = $encrypted[16..($encrypted.Length - 1)]

 

        # 2. Replicate OpenSSL EVP_BytesToKey (MD5)

        $secretBytes = [System.Text.Encoding]::UTF8.GetBytes($secret)

        $keyIV = @()

        $prev = @()

        while ($keyIV.Count -lt 48) {

            $md5 = [System.Security.Cryptography.MD5]::Create()

            $input = $prev + $secretBytes + $salt

            $prev = $md5.ComputeHash($input)

            $keyIV += $prev

        }

 

        # 3. Assign Key (32 bytes) and IV (16 bytes)

        $key = $keyIV[0..31]

        $iv  = $keyIV[32..47]

 

        # 4. Decrypt using .NET AES libraries

        $aes = [System.Security.Cryptography.Aes]::Create()

        $aes.Mode    = [System.Security.Cryptography.CipherMode]::CBC

        $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

        $aes.Key     = $key

        $aes.IV      = $iv

 

        $decryptor = $aes.CreateDecryptor()

        $decrypted = $decryptor.TransformFinalBlock($encryptedData, 0, $encryptedData.Length)

 

        return [PSCustomObject]@{

            Success          = "True"

            DecryptedContent = [System.Text.Encoding]::UTF8.GetString($decrypted)

        }

    }

    catch {

        return [PSCustomObject]@{

            Success = "False"

            Message = $_.Exception.Message

        }

    }

}

 

$myEncryptedString = "xxxxxx..." # The Base64 from your external tool

$mySecretPassword = "MySuperSecret" # The shared secret

 

# This line is where the function is called

$result = Decrypt-AES -encryptedResponse $myEncryptedString -secret $mySecretPassword

 

# 3. THE OUTPUT  converting to json to know the status of powershell

$result | ConvertTo-Json -Depth 5

 

 

Implementation Best Practices

Use Flow Designer

Instead of hardcoding the password in the script, pass it as an Input Variable in your Flow Designer PowerShell step. You should retrieve the master secret from the Discovery Credentials (discovery_credentials) table using the "Get Credential" action or from the system proper you have already stored the secret value.

Why use .NET instead of third-party libraries?

By using System.Security.Cryptography, you don't have to install any modules (like ActiveDirectory or OpenSSL-Win64) on your MID Servers. This makes your ServiceNow integration "infrastructure-agnostic" as long as the MID Server is running on Windows.

Summary

This approach ensures your secret rotation flows are secure and compliant with standard encryption formats. It allows ServiceNow to act as a secure consumer of secrets without requiring the external team to change their security posture.

Note: This works on Windows Midserver only

Tags: #PowerShell #Security #Integration #MIDServer #AES256 #OpenSSL

2 REPLIES 2

HaimNizri
Tera Contributor

Nice writeup on the OpenSSL decryption challenge. The EVP_BytesToKey implementation looks solid.

One thing to watch out for - you might want to add some validation on the encrypted input before processing:

```powershell
# Add this before the salt extraction
if ($encrypted.Length -lt 16 -or
[System.Text.Encoding]::ASCII.GetString($encrypted[0..7]) -ne "Salted__") {
throw "Invalid OpenSSL format - missing Salted__ header"
}
```

Also consider wrapping the AES object in a `using` block or explicit disposal to avoid memory leaks on high-volume flows:

```powershell
$aes = [System.Security.Cryptography.Aes]::Create()
try {
# your decryption logic
$decrypted = $decryptor.TransformFinalBlock($encryptedData, 0, $encryptedData.Length)
return [PSCustomObject]@{
Success = "True"
DecryptedContent = [System.Text.Encoding]::UTF8.GetString($decrypted)
}
} finally {
$aes.Dispose()
$decryptor.Dispose()
}
```

For the Flow Designer integration, you can make this even cleaner by creating a reusable subflow that handles the credential retrieval and decryption in one step. That way teams don't have to remember the two-step process each time.

The MD5-based key derivation is deprecated in newer OpenSSL versions, so if your external tools ever migrate to PBKDF2, you'll need to update the KDF logic. But for legacy compatibility this approach works well.

**If you find my answer useful, please mark it as Helpful and Correct. 😊**

Yes those are valid points you mentioned 
Thank you!