【问题标题】:Converting a hex string to base 64 in PowerShell在 PowerShell 中将十六进制字符串转换为 base 64
【发布时间】:2021-09-30 19:25:58
【问题描述】:

我正在尝试在 PowerShell 中复制以下 Python 代码段的功能:

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()

它需要一个 MAC 地址,删除分隔符,将其转换为十六进制,然后是 base64。 (我没有编写 Python 函数,也无法控制它或它是如何工作的。)

例如,MAC 地址AA:BB:CC:DD:E2:00 将转换为AABBCCDDE200,然后转换为b'\xaa\xbb\xcc\xdd\xe2\x00',最后作为输出b'qrvM3eIA'。我尝试做类似的事情:

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

但这会产生MethodException: Cannot find an overload for "ToString" and the argument count: "1".,我不确定它在寻找什么。我发现使用该调用的所有示例都只有一个参数。这有效:

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

但显然不会先将其转换为十六进制,因此会产生不正确的结果。任何帮助表示赞赏。

【问题讨论】:

  • 使用$bytes.Bytes方法怎么样?例如运行:[System.Convert]::ToBase64String($bytes.Bytes).
  • MAC 地址已经是十六进制。 python 脚本看起来像它解码 MAC 从十六进制到 UTF8,然后将字节编码为 base64,就像你在 powershell 中的 [System.Convert] 代码一样。
  • 另外,使用$bytes.Bytes 将修复您看到的错误,但它等效于UTF8.GetBytes 方法
  • 很高兴了解.Bytes,@Cpt.Whale;请注意,在 Windows PowerShell 中,它是 - 有损 - ASCII.GetBytes 方法。虽然这种区别在手头的情况下并不重要,但请注意,在这种情况下使用 .Bytes工作,因为您将有效地获得反映 ASCII 代码点的字节值 个字符,例如 A - 而需要将这些字符解释为 hex 数字

标签: powershell base64 hex


【解决方案1】:
# Remove everything except word characters from the string.
# In effect, this removes any punctuation ('-', ':', '.')
$sanitizedHexStr = 'AA:BB:CC:DD:E2:00' -replace '\W'

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

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

有关用于创建 $bytes 数组的技术的说明,以及更简单的 PowerShell (Core) 7.1+ / .NET 5+ 替代方案(简称:[System.Convert]::FromHexString('AABBCCDDE200')) ,见this answer


至于你尝试了什么

Format-Hex返回字节数组(直接),其主要目的是可视化十六进制格式的输入数据供人类观察者使用.

一般来说,Format-* cmdlet 输出对象的唯一目的是为 PowerShell 的输出格式化系统提供格式化指令 - 请参阅 this answer。简而言之:永远只使用Format-* cmdlet 来格式化数据用于显示,从不用于后续编程处理

也就是说,Format-Hex 的特定情况下,输出对象[Microsoft.PowerShell.Commands.ByteCollection] 类型,确实包含有用的数据,并且确实包含输入字符串.Bytes 属性的转码字符的字节,正如Cpt.Whale 指出的那样。

但是,$bytes = ($sanitizedHexStr | Format-Hex).Bytes 在您的情况下不起作用,因为您将有效地获得反映字符的 ASCII 代码点 的字节值,例如 A (见下文) - 而您需要将这些字符解释为 hex 数字

但即使在一般情况下我建议不要依赖Format-Hex 进行到字节数组的转换

  • 如前所述,从哲学上讲,Format-* cmdlet 的目的是产生 for-display 输出,而不是 data,值得观察这种区别,尽管有这个例外 - 输出对象的类型可以被视为一个实现细节

  • Format-Hex 首先应用固定字符转码将字符串转换为字节(例如,您无法获得.NET字符串的字节表示原样,基于 UTF-16 代码单元),以及 Windows PowerShellPowerShell (Core) 之间的固定转码不同

    • 在 Windows PowerShell 中,.NET 字符串被转码为 ASCII(!),导致非 ASCII 范围的字符丢失 - 它们被转码为文字 ?

    • 在 PowerShell (Core) 中,通过转码为 UTF-8 可以避免该问题。


System.BitConverter.ToString 失败,因为您的代码中的 $bytes 本身不是字节数组 ([byte[]]),只有它的 .Bytes 属性值是(但不包含感兴趣的值)。

也就是说,您不希望将字节重新转换为 字符串,您希望将字节直接转换为 Base64 编码,如上所示。

【讨论】:

  • 很高兴知道。我绝对觉得它应该是标准的,所以我很高兴他们更新了 API 以支持它。 PS Core 很容易成为未来。再次感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 2018-01-31
  • 2018-01-22
  • 1970-01-01
  • 2013-02-07
  • 2022-07-22
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
相关资源
最近更新 更多