Converting a hex string to base 64 in PowerShell

Grant Curell

I'm trying to replicate the functionality of the following Python snippit in PowerShell:

allowed_mac_separators = [':', '-', '.']
for sep in allowed_mac_separators:
    if sep in mac_address:
        test = codecs.decode(mac_address.replace(sep, ''), 'hex')
        b64_mac_address = codecs.encode(test, 'base64')
        address = codecs.decode(b64_mac_address, 'utf-8').rstrip()

It takes a MAC address, removes the separators, converts it to hex, and then base64. (I did not write the Python function and have no control over it or how it works.)

For example, the MAC address AA:BB:CC:DD:E2:00 would be converted to AABBCCDDE200, then to b'\xaa\xbb\xcc\xdd\xe2\x00', and finally as output b'qrvM3eIA'. I tried doing something like:

$bytes = 'AABBCCDDE200' | Format-Hex
[System.BitConverter]::ToString($bytes);

but that produces MethodException: Cannot find an overload for "ToString" and the argument count: "1". and I'm not really sure what it's looking for. All the examples I've found utilizing that call only have one argument. This works:

[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('AABBCCDDE200'))

but obviously doesn't convert it to hex first and thus yields the incorrect result. Any help is appreciated.

mklement0
# Remove everything except hex digits from the string.
$sanitizedHexStr = 'AA:BB:CC:DD:E2:00' -replace '[^0-9a-f]'

# Convert all hex-digit pairs in the string to an array of bytes.
$bytes = [byte[]] ($sanitizedHexStr -split '(..)' -ne '' -replace '^', '0x')

# Get the Base64 encoding of the byte array.
[System.Convert]::ToBase64String($bytes)

For an explanation of the technique used to create the $bytes array, see this answer.


As for what you tried:

Format-Hex does not return an array of bytes, it visualizes the input data in hex format for the human observer.

In general, Format-* cmdlets output objects whose sole purpose is to provide formatting instructions to PowerShell's output-formatting system - see this answer. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing.

That said, in the particular case of Format-Hex the output objects, which are of type [Microsoft.PowerShell.Commands.ByteCollection], do contain useful data, and do contain the bytes of interest in their .Bytes property, as Cpt.Whale points out.

While $bytes = ($sanitizedHexStr | Format-Hex).Bytes would have worked in this case, I suggest not relying on Format-Hex for to-byte-array conversions in general:

  • On a philosophical note, as stated, the purpose of Format-* cmdlets is to produce for-display output, not data, and it's worth observing this distinction, this exception notwithstanding.

  • Format-Hex converts strings to bytes based on first applying a fixed character transcoding (e.g., you couldn't get the byte representation of a .NET string as-is, based on UTF-16 code units), and that fixed transcoding differs between Windows PowerShell and PowerShell (Core):

    • In Windows PowerShell, the .NET string is transcoded to ASCII(!), resulting in the loss of non-ASCII-range characters - they are transcoded to literal ?

    • In PowerShell (Core), that problem is avoided by transcoding to UTF-8.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related