AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79566585
Accepted
vamsiampolu
vamsiampolu
Asked: 2025-04-10 20:04:14 +0800 CST2025-04-10 20:04:14 +0800 CST 2025-04-10 20:04:14 +0800 CST

解码 base64 字符串并使用 xxd 将其编码为十六进制

  • 772

首先,我获取一个 base64 编码的字符串并对其进行解码:

local base64_str="OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw="
echo "${base64_str}" | base64 --decode > foo.txt

二进制文件的大小为 32 字节,基于:wc -c < foo.txt

我使用xxd将文件中的值编码为十六进制格式:

xxd -p ./foo.txt ./foo.hex.txt

文件 foo.hex.txt 中的十六进制值为:

3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66a
c13c

编码哈希文件的大小为 66 字节,使用wc -c < foo.hex.txt

我想将 base64 字符串转换为十六进制,使其保留为 32 字节字符串,以便我可以与 openssl 一起使用 aes-256 密码进行加密和解密。

local iv_hex=$(base64_to_hex "${iv}")
local key_hex=$(base64_to_hex "${key}")

openssl enc -aes-256-ctr -K "${key_hex}" -iv "${iv_hex}" -in "${input_file}" -out "${output_file}"
bash
  • 2 2 个回答
  • 111 Views

2 个回答

  • Voted
  1. F. Hauri - Give Up GitHub
    2025-04-10T22:42:54+08:002025-04-10T22:42:54+08:00

    将小型 base64 编码字符串转换为十六进制

    1. 减少分叉

    接受的答案确实提供了一个有很多分支的解决方案!我讨厌没用的叉子!

    这是我的简短的base64 到十六进制转换器:

    b64toHex() {
        local _arLines
        mapfile -t _arLines < <(base64 -d <<< "$2" | xxd -p)
        printf -v "${1:-hexString}" %s "${_arLines[@]}"
    }
    

    为了避免类似 fork 的情况myVar=$(myFunc args),此函数只会填充一个变量,而不会打印出任何内容。

    b64toHex myVar "OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw="
    echo $myVar
    
    3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66ac13c
    

    然后你可以使用:

    b64toHex iv_hex "${iv}"
    b64toHex key_hex "${key}"
    

    请参阅本文底部以了解执行时间比较。

    2.纯bash方式:

    这不依赖于xxd任何base64安装。(而且无需 fork,比运行 3 个 fork 快得多!如果您打算重复运行此操作,请记住这一点!)

    来自这个: Bash 脚本 - 将编码的字符串解码为字节数组,在我的网站上:base64decoder.sh.txt,base64decoder.sh,有一个非常小的修改**:

    **第 41 行:
    - ((_ar==0)) && printf -v _res %b "${_res[@]/#/\\x}"
    + ((_ar==0)) && printf -v _res %s "${_res[@]}"

    首先准备一个只读数组:

    declare -a B64=( {A..Z} {a..z} {0..9} + / '=' )
    declare -Ai 'B64R=()'
    for i in "${!B64[@]}"; do B64R["${B64[i]}"]=i%64; done
    declare -r B64R
    unset B64
    

    然后b64ToHex函数:

    b64ToHex() {
        local _4B _Tail _hVal _v _opt OPTIND
        local -i iFd _24b _ar
        while getopts "av:" _opt; do case $_opt in
            a) _ar=1;; v) _v=${OPTARG};; *) return 1;; esac; done
        shift $((OPTIND-1))
        if [[ $_v ]];then local -n _res=${_v}; else local _res; fi
        if [[ $1 ]]; then    exec {iFd}<<<"$1"          # Open Input FD from string
        else                 exec {iFd}<&0        ; fi  # Open Input FD from STDIN
        _res=()
        while read -rn4 -u $iFd _4B; do
            if [[ "$_4B" ]]; then
                _Tail=$_4B
                _24b=" B64R['${_4B::1}'] << 18 | B64R['${_4B:1:1}'] << 12 |
                       B64R['${_4B:2:1}'] << 6 | B64R['${_4B:3:1}'] "
                printf -v _hval %02x\  $((_24b>>16)) $((_24b>>8&255)) $((_24b&255))
                read -ra _hval <<<"$_hval"
                _res+=("${_hval[@]}")
            fi
        done
        exec {iFd}<&-
        _Tail=${_Tail##*([^=])}
        while [[ $_Tail ]]; do
            unset "_res[-1]"
            _Tail=${_Tail:1}
        done
        ((_ar==0)) && printf -v _res %s "${_res[@]}" && _res=("${_res[0]}")
        [[ -z $_v ]] && echo "${_res[@]}"
    }
    

    如果已知bash循环很慢,那么仅对 32 字节进行循环将比运行四个 fork 快得多,而且系统扩展性更低!

    从STDIN使用:

    b64ToHex <<<"OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw="
    
    3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66ac13c
    

    从一个论点来看:

    b64ToHex "OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw="
    
    3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66ac13c
    

    分配变量:

    b64ToHex -v someVar "OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw="
    echo "$someVar"
    
    3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66ac13c
    

    然后从,到变量:

    b64ToHex -v iv_hex "${iv}"
    b64ToHex -v key_hex "${key}"
    

    注意:这是在没有任何分叉的情况下完成的。

    为了好玩:检索原始 base64 字符串,使用 bash V5.1+,您可以:

    shopt -s extglob
    printf %b ${someVar//??/\\x& } | base64
    
    OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw=
    

    3. 纯 bash 方式,但使用 bash V5.2+

    相同的脚本,但通过使用patsub_replacement和mapfile,我可以不使用任何bash循环来完成此操作!

    declare -a B64=( {A..Z} {a..z} {0..9} + / '=' )
    printf -v _b64_tstr '["\44{B64[%d]}"]=%%d%%%%64 ' {0..64}
    # shellcheck disable=SC2059  # format is variable.
    printf -v _b64_tstr "$_b64_tstr" {0..64}
    declare -Ai "B64R=($_b64_tstr)"
    unset B64 _b64_tstr
    declare -r B64R
    
    b64ToHex52() {
        local _line _Tail _v _opt OPTIND _resArry
        local -i iFd _ar
        while getopts "av:" _opt; do case $_opt in
            a) _ar=1;; v) _v=${OPTARG};; *) return 1;; esac; done
        shift $((OPTIND-1))
        if [[ $_v ]];then local -n _res=${_v}; else local _res; fi
        if [[ $1 ]]; then    exec {iFd}<<<"$1"     # Open Input FD from string
        else                 exec {iFd}<&0   ; fi  # Open Input FD from STDIN
        mapfile -tu $iFd _lines
        read -ra _resArry <<<"${_lines[*]//?/& }"
        printf -v _tmpStr '"B64R[%s]<<18|B64R[%s]<<12|B64R[%s]<<6|B64R[%s]" ' \
               "${_resArry[@]}"
        local -ia "_tmpArry=($_tmpStr)"
        printf -v _tmpStr '%06x' "${_tmpArry[@]}"
        read -ra _res <<<"${_tmpStr//??/& }"
        exec {iFd}<&-
        _Tail=${_lines[-1]##*([^=])}
        _res=("${_res[@]::${#_res[@]}-${#_Tail}}")
        ((_ar==0)) && printf -v _res %s "${_res[@]}" && _res=("${_res[0]}")
        [[ -z $_v ]] && echo "${_res[@]}"
    }
    

    4. 执行时间对比

    好吧,现在通过重复进行相同的转换来计算执行时间,进行一点比较测试。

    我现在有4个功能:

    1. b64toHex我的版本使用base64和xxd
    2. b64ToHex我的纯bash版本(注意上方T)
    3. b64ToHex52我的纯bash使用 bash 版本 5.2+
    4. base64_to_hex来自接受的答案。

    这是我的小测试功能:

    testB64decoders(){ 
        local TIMEFORMAT='r %3lR,  u %3lU,  s %3lS, p %P' bunch \
            inString="${2:-SGVsbG8gd29ybGQhIFRoaXMgaXMgYSB0ZXN0IHN0cmluZy4=}"
        printf -v bunch '%*s' ${1:-100} ''
        mapfile -t bunch <<<"${bunch// /$'\n'}"
        printf ' - %-29s: ' "3 fork (base64 | xxd)";
        time for i in "${bunch[@]}"; do b64toHex hx "$inString"; done
        printf ' - %-29s: ' "Pure bash";
        time for i in "${bunch[@]}"; do b64ToHex -v Hx "$inString"; done;
        printf ' - %-29s: ' "Pure bash V5.2+";
        time for i in "${bunch[@]}"; do b64ToHex52 -v Hx5 "$inString"; done;
        printf ' - %-29s: ' "5 fork =\$(echo| base64 | xxd)";
        time for i in "${bunch[@]}"; do hex=$(base64_to_hex "$inString"); done;
        [[ $hx == "$hex" ]] && [[ $Hx == "$hx" ]] && [[ $Hx5 == "$hx" ]] &&
            printf -v inString '%b' ${hx//??/\\x&} &&
            printf 'Hopefully result strings are same (%s).\n' "${inString@Q}"
    }
    

    让我们用一小千个操作来展示:

    testB64decoders 1000
    

    可能会产生类似这样的结果:

     - 3 fork (base64 | xxd)        : r 0m2.032s,  u 0m2.315s,  s 0m0.699s, p 148.32
     - Pure bash                    : r 0m0.965s,  u 0m0.735s,  s 0m0.213s, p 98.14
     - Pure bash V5.2+              : r 0m0.571s,  u 0m0.477s,  s 0m0.088s, p 98.91
     - 5 fork =$(echo| base64 | xxd): r 0m2.433s,  u 0m3.242s,  s 0m0.989s, p 173.92
    

    其中r实际、:用户、:系统时间和:CPU百分比为:usp100 * ( u + s ) / r

    • 纯bash方法更快,
    • 使用 bash 5.2+ 的纯bash方法明显更快,
    • 版本使用xxd和base64只有两个 fork 甚至会比
    • 版本使用了四个fork(一个子shell,用于运行另外三个 fork,分别用于xxd、base64和tr)。它们是最慢的,而且是的:另外两个 fork 确实占用系统资源。

    注意:在多核系统上,由于并行化,user时间大于时间real

    在我的Raspberry-Pi II 型号 B上,我必须将测试减少到 20 个循环。

    testB64decoders 20
    

    在我的RPi II上产生了:

     - 3 fork (base64 | xxd)        : r 0m2.134s,  u 0m0.289s,  s 0m0.704s, p 46.55
     - Pure bash                    : r 0m1.931s,  u 0m0.890s,  s 0m0.104s, p 51.49
     - Pure bash V5.2+              : r 0m0.874s,  u 0m0.354s,  s 0m0.078s, p 49.36
     - 5 fork =$(echo| base64 | xxd): r 0m3.399s,  u 0m0.787s,  s 0m0.847s, p 48.06
    Hopefully result strings are same ('Hello world! This is a test string.').
    
    • 4
  2. Best Answer
    pynexj
    2025-04-10T20:48:51+08:002025-04-10T20:48:51+08:00

    xxd -p\n输出中可能有字符,因此您需要删除它们:

    base64_to_hex()
    {
        echo "$1" | base64 --decode | xxd -p | tr -d '\n'
    }
    

    使用您的 base64 字符串作为示例:

    $ hex=$( base64_to_hex OQbb8rXnj/DwvglW018uP/1tqldwiJMbjxBhX7ZqwTw= )
    $ echo $hex
    3906dbf2b5e78ff0f0be0956d35f2e3ffd6daa577088931b8f10615fb66ac13c
    
    • 3

相关问题

  • (macOS Bash) 2个看似相同的字符串并不相等,仅通过“set -x”显示差异

  • Xargs:尽管扩展了别名,但别名替换仍失败

  • Linux 环境中 $PATH 和 ${PATH:+:${PATH}} 的区别

  • awk 查找并替换为正则表达式和环境变量

  • 如何在 bash 中对任意长度的编号、分隔字母数字字符串的文件名进行零填充?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve