3

Am trying to obsfuscate the API key from zscaler

https://help.zscaler.com/zia/api-getting-started, but they have no documentation for powershell.

I did the conversion from javascript to powershell : Here the function for your information

Function Obfuscate {

PARAM (

[Parameter(Mandatory=$true,HelpMessage="apiKey")][String] $key,

[Parameter(Mandatory=$true,HelpMessage="Timestamp")]$timestamp

)

$apiKey=""

$high=$Timestamp.substring($timestamp.length -6)

$low=$high -shr 1

$low=$low.ToString()

While ($low.length -lt 6) {$low="0"+$low}

For ($i=0;$i -lt $high.length; $i++) {

$apiKey+=$key.substring($high.substring($i,1) -shr 0,1)

}

For ($i=0;$i -lt $low.length; $i++) {

$apiKey+=$key.substring(($low.substring($i,1) -shr 0)+2,1)

}

return $apiKey

}

It remains only one problem , that is very annoying :

Date.now() (for the timestamp variable) in javascript/java/python and son return a 13 digit number (1519984360183) (which is supposed to be time in second since 1970/01/01 00:00:00:00)

The similar function in powershell :

$timestamp=([Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))).tostring()

or

$timestamp = (Get-Date -UFormat %s)

Return a 15 digits number

Running the script to send a post request with a 15 digits timestamp give an error as Zscaler server doesn’t recognize the obfuscated api key.

Any idea ?

1 Answer 1

4

Note: The answer below corrects your own approach, but note that in Windows PowerShell 5.1 and PowerShell (Core) a much simpler solution is available:

# PSv5.1+
$timestamp = [datetimeoffset]::Now.ToUnixTimeMilliSeconds()

Note: The above, which directly returns whole seconds (as a [long] instance) implicitly performs (half-away-from-zero) rounding on the fractional seconds part to return an integer representation, which differs from your own truncation approach.


Fixing your attempt:

  • Get-Date -UFormat %s returns a (stringified) value in (fractional) seconds,
  • whereas JavaScript uses (integral) milliseconds.

Both are representations of Unix (epoch) time, but in different units (and with different number types).

Therefore, you need to multiply by 1000 and convert the result to an integer (simply cast the result to [string] or apply .ToString() if you ultimately need a string representation):

$timestamp = [Math]::Floor(
  1000.0 * [double]::Parse((Get-Date ([datetime]::UtcNow) -UFormat %s))
)
  • ([datetime]::UtcNow) returns the current point in time as a UTC timestamp, which is necessary, because Unix time is expressed in UTC; it is the shorter (and faster) equivalent of (Get-Date).ToUniversalTime().

    • Note: To get the correct result in Windows PowerShell you must provide an UTC date as input (a [datetime] instance whose .Kind value is Utc). This is no longer required in PowerShell (Core) v7+.
  • [double]::Parse() parses Get-Date's string output into a [double] instance, using culture-sensitive parsing (whereas a [double] cast would be culture-invariant and would only accept . as the decimal mark).

    • Note that in PowerShell (Core) v7+ Get-Date -UFormat %s now more sensibly returns a string representing an integer, i.e. whole seconds.
  • [Math]:Floor() then truncates that double (drops the fractional part); the result is a [double], but without decimal places. if you need an actual integer type, cast to [long].

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.