尧图精选

ESP-IDF NVS 分区生成工具 nvs_partition_gen.py 详解:从 CSV 键值对生成、加密与解密 NVS 闪存分区

🕒 发布时间:2026/9/14 9:59:03 📁 来源:尧图网络
ESP-IDF NVS 分区生成工具 nvs_partition_gen.py 详解从 CSV 键值对生成、加密与解密 NVS 闪存分区【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf在 ESP-IDFEspressif IoT Development Framework中Non-Volatile StorageNVS非易失性存储是跨重启持久化配置数据的核心组件。但在 ODM/OEM 量产场景中厂商往往需要在产线上为每台设备烧录不同的序列号、校准参数或证书等数据而不能依赖设备开机后的运行时写入。本文介绍的 NVS 分区生成程序NVS Partition Generator正是解决这一问题的工具它根据 CSV 文件中的键值对直接生成与 nvs_flash 组件 结构兼容的二进制分区文件支持多页 blob、XTS-AES 加密以及基于 HMAC 的密钥保护方案。读完本文你将掌握 CSV 输入文件的完整格式规范、四个子命令generate / generate-key / encrypt / decrypt的全部参数并理解生成分区内部的条目结构与 CMake 集成方式。工具定位与工作原理NVS 分区生成程序的入口脚本位于 nvs_partition_gen.py。从源码看该脚本本身只有一行核心逻辑if __name__ __main__: sys.exit(subprocess.run([sys.executable, -m, esp_idf_nvs_partition_gen] sys.argv[1:]).returncode)它是一个薄封装层真正的实现由 pip 包esp-idf-nvs-partition-gen承担该包在 tools/requirements/requirements.core.txt 中声明执行时通过python -m以模块方式调用。因此只要 IDF 工具链的 Python 依赖已安装直接运行脚本即可。该程序的典型应用场景是设备生产时的外部烧录数据制造商使用同一份应用固件通过自定义参数如序列号为每台设备生成内容不同的 NVS 二进制分区再用烧录工具将其单独写入分区表中的 NVS 分区。相比运行时调用nvs_set_str()等 API这种方式让设备在出厂前即持有完整配置避免首次启动的初始化窗口。准备工作在加密模式下使用该程序需要额外安装cryptographyPython 包XTS-AES 加解密依赖它。仓库根目录下的 Python 依赖清单当前版本位于tools/requirements/目录包含工具运行所需的包建议先完整安装。CSV 文件格式输入 CSV 文件每行包含四个以逗号分隔的参数具体含义如下表序号参数描述说明1Key主键应用程序可通过查询此键来获取数据长度不超过 15 个字符含结尾的 NULL见下文结构分析2Type支持file、data和namespace与 NVS API 中的条目类型一致3Encoding决定二进制文件中 value 被编码成的类型支持u8、i8、u16、i16、u32、i32、u64、i64、string、hex2bin、base64和binarystring与binary的区别在于string数据以 NULL 字符结尾binary数据则不是。file类型当前仅支持hex2bin、base64、string和binary编码4Value数据值namespace条目的encoding和value应为空固定值单元格内容会被忽略需要注意的格式约束CSV 文件的第一行应始终为列标题key,type,encoding,value不可省略逗号,前后不能有空格每行末尾也不能有多余空格字符串值中若包含逗号或换行需用双引号包裹仓库中的示例文件即采用了多行字符串写法。此类 CSV 文件的结构示例如下key,type,encoding,value -- 列标题 namespace_name,namespace,, -- 第一个条目为 namespace key1,data,u8,1 key2,file,string,/path/to/file仓库内提供了三个可直接参考的示例文件位于 nvs_partition_generator 目录sample_singlepage_blob.csv覆盖 u8/i8/u16/u32/i32 数值型键、string、hex2bin、base64以及file类型下分别以 hex、base64、string、binary 编码引用 testdata 目录中文件的完整示例sample_multipage_blob.csv与上者类似但引用的是可跨多页的大 blobtestdata/sample_multipage_blob.binsample_val.csv一个命名空间storage下的最简键值集合。file类型条目的 Value 是文件路径而非内联数据例如hexFileKey,file,hex2bin,testdata/sample.hex——生成器会读取该文件、按编码解析后写入分区。NVS 条目与命名空间的关联规则CSV 文件中的条目与 NVS 命名空间namespace的对应关系遵循顺序生效规则CSV 文件中第一个条目应始终为namespace类型声明初始命名空间如 CSV 文件中出现命名空间条目后续所有条目均被视为该命名空间的一部分直至遇到下一个命名空间条目找到新命名空间条目后后续所有条目都会归属到新的命名空间。这意味着命名空间不是每行的属性而是作用域概念key,type,encoding,value storage,namespace,, u8_key,data,u8,255 # 归属 storage 命名空间 wifi,namespace,, ssid,data,string,my-wifi # 归属 wifi 命名空间分区内部结构条目如何编码生成器输出的二进制分区由 4096 字节0x1000的页组成。从仓库中用于校验生成结果的测试代码 test_nvs_gen_check.py 的create_entry_data_bytearray函数可以印证单条目的二进制布局每个条目 32 字节偏移长度内容01 字节命名空间索引namespace_index11 字节条目类型data/string/file 等21 字节跨度spanblob 占用的连续条目数31 字节blob 数据块索引chunk_index4–74 字节CRC32初值0xFFFFFFFF覆盖前 4 字节 键 值8–2316 字节键NULL 字节填充至 16 字节且末位强制为 024–318 字节值数据定长整数按小端序存储字符串/文件条目为指针信息这解释了 CSV 格式中的两条隐性约束键被 NULL 填充到 16 字节所以键名实际最长 15 个字符定长数值只取低 8 字节写入与编码选择u8/i8/u16/i16/u32/i32共同决定有效位宽。string与binary的差别则体现在值末尾是否追加 NULL 终止符上。支持多页 blob默认情况下版本 2二进制 blob 可以跨多个 4096 字节的页存储通过条目中的span占用的条目数和chunk_index数据块索引串联。版本 1 对应旧版格式禁用多页 blob单个 blob 只能落在单页内——仓库中保留了旧格式参考文件 part_old_blob_format.bin 供比对。两个版本的生成命令# 版本 1禁用多页 blob python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 --version 1 # 版本 2启用多页 blob默认 python nvs_partition_gen.py generate sample_multipage_blob.csv sample.bin 0x4000 --version 2程序命令总览总用法::python nvs_partition_gen.py [-h] {generate,generate-key,encrypt,decrypt} ...参数描述-h/--help显示帮助信息并退出四个子命令参数描述generate生成明文NVS 分区generate-key生成加密密钥分区encrypt加密 NVS 分区decrypt解密 NVS 分区运行python nvs_partition_gen.py {command} -h可查看各子命令的完整帮助。子命令一generate生成明文 NVS 分区默认模式python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR] input output size位置参数参数描述input待解析的 CSV 文件路径outputNVS 二进制文件的输出路径sizeNVS 分区大小字节为单位且为 4096 的整数倍可选参数参数描述-h/--help显示帮助信息并退出--version {1,2}设置多页 blob 版本默认为版本 2。版本 1禁用多页 blob版本 2启用多页 blob--outdir OUTDIR输出目录用于存储创建的文件默认当前目录基本运行命令python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000NVS 分区最小尺寸为 0x3000 字节。将生成的二进制文件烧录至设备时请确保分区表中的 NVS 分区大小与应用的 sdkconfig 设置一致例如CONFIG_NVS_FLASH_ENCRYPTION_ENABLED等选项要与分区是否加密匹配。子命令二generate-key生成加密密钥支持 HMAC 外设的 SoC 上的用法::python nvs_partition_gen.py generate-key [-h] [--key_protect_hmac] [--kp_hmac_keygen] [--kp_hmac_keyfile KP_HMAC_KEYFILE] [--kp_hmac_inputkey KP_HMAC_INPUTKEY] [--keyfile KEYFILE] [--outdir OUTDIR]不支持 HMAC 外设的 SoC 上的用法::python nvs_partition_gen.py generate-key [-h] [--keyfile KEYFILE] [--outdir OUTDIR]通用可选参数参数描述-h/--help显示帮助信息并退出--keyfile KEYFILE加密密钥分区文件的输出路径--outdir OUTDIR输出目录默认当前目录仅适用于 HMAC 方案的可选参数SOC_HMAC_SUPPORTED参数描述--key_protect_hmac设置后使用基于 HMAC 的 NVS 加密密钥保护方案否则使用基于 flash 加密的默认方案--kp_hmac_keygen为基于 HMAC 的加密方案生成 HMAC 密钥--kp_hmac_keyfile KP_HMAC_KEYFILEHMAC 密钥文件的输出路径--kp_hmac_inputkey KP_HMAC_INPUTKEY包含 HMAC 密钥的文件用于生成 NVS 加密密钥运行命令# 仅生成flash 加密方案下的加密密钥分区 python nvs_partition_gen.py generate-key # 为基于 HMAC 的方案同时生成 HMAC 密钥和 NVS 加密密钥 python nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen # 基于用户已有的 HMAC 密钥生成 NVS 加密密钥 python nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin说明--key_protect_hmac --kp_hmac_keygen会生成outdir/keys/keys-timestamp.bin格式的加密密钥和outdir/keys/hmac-keys-timestamp.bin格式的 HMAC 密钥可将自定义文件名作为参数提供给 HMAC 密钥和加密密钥通过--keyfile/--kp_hmac_keyfile。加密方案的整体原理XTS-AES-128、密钥分区结构、flash 加密与 HMAC 两种密钥保护方式的区别详见 NVS 加密指南。子命令三encrypt生成 NVS 加密分区支持 HMAC 外设的 SoC 上的用法::python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen] [--keyfile KEYFILE] [--inputkey INPUTKEY] [--outdir OUTDIR] [--key_protect_hmac] [--kp_hmac_keygen] [--kp_hmac_keyfile KP_HMAC_KEYFILE] [--kp_hmac_inputkey KP_HMAC_INPUTKEY] input output size不支持 HMAC 外设的 SoC 上的用法去掉 HMAC 相关参数::python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen] [--keyfile KEYFILE] [--inputkey INPUTKEY] [--outdir OUTDIR] input output size位置参数与generate相同inputCSV 路径、outputNVS 二进制输出路径、size分区大小4096 的整数倍。通用可选参数参数描述-h/--help显示帮助信息并退出--version {1,2}多页 blob 版本设置默认版本 2--keygen生成 NVS 分区加密密钥--keyfile KEYFILE密钥文件的输出路径--inputkey INPUTKEY内含 NVS 分区加密密钥的文件--outdir OUTDIR输出目录默认当前目录HMAC 方案专属参数与generate-key中的--key_protect_hmac/--kp_hmac_keygen/--kp_hmac_keyfile/--kp_hmac_inputkey含义相同。典型用法# 1. 由生成程序生成加密密钥同时加密分区 python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen # 创建的加密密钥格式为 outdir/keys/keys-timestamp.bin # 2. HMAC 方案同时生成加密密钥和 HMAC 密钥 python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 \ --keygen --key_protect_hmac --kp_hmac_keygen # 3. HMAC 方案使用用户提供的 HMAC 密钥派生加密密钥 python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 \ --keygen --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin # 4. 生成密钥并存储到自定义文件 python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 \ --keygen --keyfile sample_keys.bin # 此时密钥位于 outdir/keys/sample_keys.bin # 5. 将已有的加密密钥文件作为二进制输入进行加密 python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 \ --inputkey sample_keys.bin注意加密密钥存储在新建文件的keys/目录下与 NVS 密钥分区结构兼容即该密钥文件本身可作为独立的密钥分区烧录。密钥分区结构的详细说明见 NVS 加密指南 中的nvs_encr_key_partition章节。仓库测试数据中也提供了示例密钥文件 testdata/sample_encryption_keys.bin 与 testdata/sample_hmac_key.bin 可供解密验证时参考。子命令四decrypt解密 NVS 分区python nvs_partition_gen.py decrypt [-h] [--outdir OUTDIR] input key output位置参数参数描述input待解析的 NVS 加密分区文件路径key含有解密密钥的文件路径output已解密的二进制文件输出路径可选参数参数描述-h/--help显示帮助信息并退出--outdir OUTDIR输出目录默认当前目录解密命令示例python nvs_partition_gen.py decrypt sample_encr.bin sample_keys.bin sample_decr.bin与构建系统集成CMake 方式生成分区除了手动调用nvs_partition_gen.py也可以直接在组件的 CMakeLists.txt 中通过 CMake 函数生成 NVS 分区镜像其底层封装了同一生成器函数定义见 project_include.cmakenvs_create_partition_image(partition csv [FLASH_IN_PROJECT] [DEPENDS dep dep dep ...])参数描述partitionNVS 分区名分区表中的名称csv待解析的 CSV 文件路径FLASH_IN_PROJECT可选指定后将镜像纳入项目烧录清单idf.py flash时自动烧录DEPENDS可选声明该命令依赖的文件触发重新生成若不指定FLASH_IN_PROJECT镜像仍会生成但需用idf.py partition-flash手动烧录例如分区名为nvs时执行idf.py nvs-flash。该函数必须从组件的CMakeLists.txt中调用且目前仅支持非加密分区加密分区仍需手动执行encrypt子命令。生成结果的完整性校验仓库配套提供了 NVS 分区检查工具与自动化测试 test_nvs_gen_check.py它直接以模块方式导入esp_idf_nvs_partition_gen生成器将内存中的生成结果交给nvs_parser/nvs_check做结构化校验。从测试用例可以看到校验维度包括分区大小检查check_partition_size与空页存在性检查check_empty_page_present——NVS 正常运行要求分区内保留至少一个空页页 CRC 与空页内容检查check_page_crc/check_empty_page_content——每个非空页的页头 CRC 必须校验通过重复键检测identify_entry_duplicates——验证同一命名空间下不应出现重复键测试setup_bad_same_key_*系列用例精确统计了重复条目数如test_check_duplicates_bad_same_key_different_pages断言恰好发现 9 组重复键最小化 JSON 输出print_minimal_json——测试test_print_minimal_json断言输出为合法 JSON包含namespace、key、encoding、data、state、is_empty字段且 blob 数据可经 base64 解码后与原始 sample_multipage_blob.bin 逐字节一致非 ASCII 字符串的 CRC 一致性校验test_check_non_ascii_string。这说明生成器输出的分区不是黑盒二进制而是可以被解析、校验和审计的——生产流程中可用同样的解析逻辑验证烧录前的分区镜像。使用注意事项原文档明确列出的三条重要限制在实际使用中务必注意不检查重复键分区生成程序不会对重复键进行检查而是将数据同时写入这两个重复键中。请注意不要使用同名的键这也是上文重复键检测测试所针对的问题从测试代码看生成器新版本对跨页重复命名空间条目只切换当前命名空间索引而不重复写入但同名数据键仍会重复落盘。字段顺序影响空间利用率新页面创建后前一页的空白处不会再写入数据。CSV 文件中的字段须按次序排列以优化内存——将小条目数值、短字符串排在大 blob 之前能显著减少跨页碎片。暂不支持 64 位数据类型虽然 CSV 的 encoding 列列出了u64/i64但当前生成器尚不支持这两种 64 位数据类型的实际写入。其他实践要点分区大小参数size必须以 4096 为整数倍最小 0x3000生成二进制文件烧录至设备时确保与应用 sdkconfig 中 NVS 相关配置分区大小、是否启用加密、HMAC 方案一致否则nvs_flash_init()会初始化失败加密模式需安装cryptography包HMAC 相关参数--key_protect_hmac系列仅在支持 HMAC 外设的芯片上可用。小结NVS 分区生成程序将CSV 键值描述 → 可烧录 NVS 分区镜像这一量产环节工具化generate处理明文分区generate-key/encrypt/decrypt覆盖 XTS-AES 加密分区及其密钥管理含 flash 加密与 HMAC 两种密钥保护方案--version {1,2}控制多页 blob 格式配合 CMake 的nvs_create_partition_image函数可无缝嵌入构建流程。结合仓库中的示例 CSV、测试数据与nvs_check校验测试开发者可以完整复现并验证从产线烧录到设备端读取的整条数据链路。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →