How to Decrypt OpenSSL AES-256-CBC Secrets in ServiceNow via PowerShell
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 hours ago - last edited 4m ago
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:
- It prefixes the data with the string Salted__.
- It follows that with 8 bytes of random Salt.
- 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.
- 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

