简介:这份资源面向嵌入式开发与安全应用工程师,围绕Microchip ATSHA204加密芯片提供中文手册与STM32F103平台例程demo,帮助读者理解密钥存储、数据加密、哈希算法及I2C/SPI通信等安全机制,解决芯片选型、集成与调试中的实际问题。压缩包共550个文件,约14.95MB,以47个h头文件、40个c源文件、30个o目标文件、30个d依赖文件及uvprojx、uvoptx等Keil工程文件为主,另含4个pdf手册、9个sample示例、3个s汇编与若干txt说明,覆盖从源码到工程配置的完整开发链路。目前已有612人学习下载。手册系统讲解工作原理、技术规格、硬件接口与安全引擎调用方式,例程则演示STM32F103与ATSHA204的通信流程和加密功能调用,读者可据此快速搭建验证环境、对照移植代码并掌握密钥管理与数据保护思路,适合初学者入门与有经验开发者查阅。
1. 从一颗被“锁死”的加密芯片说起
如果你做过带安全认证的硬件产品,大概率遇到过这种场景:板子上的主控要和一颗加密芯片做挑战应答,结果 I2C 波形看着正常,读回来的数据却永远是0x00或者0xFF,折腾半天才发现是配置区被锁了、或者从机地址搞错了。ATSHA204 就是这类芯片里最经典的一颗——它负责密钥存储、SHA-256 摘要运算、随机数生成和一次性配置锁定,很多方案用它来做配件防伪、耗材认证、设备授权。但它的中文资料一直比较零散,数据手册是英文的,配置区那一堆 Slot、OTP、DataZone 的概念第一次看基本是懵的。
这份资源把 ATSHA204 的中文手册和 STM32 平台的例程 Demo 放在了一起,适合两类人:一类是刚接手硬件安全认证、需要快速把芯片跑通的嵌入式新手;另一类是想在 STM32 工程里集成挑战应答逻辑、做二次开发的熟手。下面我按“这芯片能干什么 → 例程怎么跑起来 → 代码怎么改”的顺序,把这份资料拆开讲一遍。
2. ATSHA204 核心机制:Slot、密钥与挑战应答链路
2.1 芯片内部到底存了什么
ATSHA204 的内部存储分成几个区,理解这几个区是后面写代码的前提。配置区(Config Zone)存放序列号、各 Slot 的访问权限、以及是否锁定等标志位;数据区(Data Zone)分成 Slot 0 到 Slot 15,每个 Slot 可以存密钥、也可以存数据;还有一块 OTP 区,只能写一次。芯片出厂时配置区是未锁定的,你可以按自己的方案写权限,一旦执行 Lock 命令,配置区就永久锁死,改不回来了。
这里有个血泪经验:很多新手拿到芯片直接跑例程,例程里如果带了 Lock 操作,跑一次之后芯片就定型了。所以第一次调试,我一般会先只跑读序列号、读随机数这类只读命令,确认 I2C 通了再动配置区。
/* 读取 ATSHA204 序列号,只读操作,不会改变芯片状态 */ uint8_t atsha204_read_sn(uint8_t *sn) { uint8_t cmd[4] = {0x00, 0x00, 0x00, 0x00}; /* 命令包占位 */ uint8_t resp[32]; /* 组包:命令字 0x02 是 Read,模式 0x80 表示读配置区 */ cmd[0] = 0x02; /* Read 命令 */ cmd[1] = 0x80; /* 读配置区 */ cmd[2] = 0x00; /* 地址低字节 */ cmd[3] = 0x00; /* 地址高字节 */ if (atsha204_send_cmd(cmd, 4) != 0) { return 1; /* I2C 发送失败 */ } if (atsha204_recv_resp(resp, sizeof(resp)) != 0) { return 2; /* 接收失败 */ } /* 序列号在返回包的第 1~4 字节,前面是长度和状态字 */ memcpy(sn, &resp[1], 4); return 0; }这段代码里cmd[0]是命令字,cmd[1]是模式,后两字节是地址。返回包第一个字节是长度,第二个字节是状态,真正的数据从第三个字节开始。参数改动的关键点在于cmd[1]:读配置区用0x80,读数据区用0x00,读 OTP 区用0x01,搞错了就会一直返回错误状态。
2.2 挑战应答是怎么算出来的
ATSHA204 最核心的用法是挑战应答。主机生成一个随机挑战(Challenge),发给芯片,芯片用内部某个 Slot 里存的密钥,对挑战做 SHA-256 运算,把结果返回。主机这边用同样的密钥和挑战自己算一遍,两边比对,一致就说明配件是正品。
这个过程里,密钥永远不出芯片,这是它比“把密钥存在主控 Flash 里”安全的地方。但要注意,参与运算的 Slot 必须配置成允许被 Nonce 和 Digest 命令使用,否则芯片会拒绝执行。配置区里每个 Slot 有独立的读写权限位,这部分在中文手册里对应“Slot 配置”那一节,建议对着手册把每个 bit 的含义过一遍。
/* 挑战应答:主机发挑战,芯片返回摘要 */ uint8_t atsha204_challenge(uint8_t *challenge, uint8_t *response) { uint8_t nonce_cmd[20]; uint8_t digest_cmd[4] = {0x08, 0x00, 0x00, 0x00}; /* Digest 命令 */ /* 第一步:把挑战作为 Nonce 发给芯片 */ nonce_cmd[0] = 0x16; /* Nonce 命令 */ nonce_cmd[1] = 0x00; /* 模式 0:直接传 32 字节 */ memcpy(&nonce_cmd[2], challenge, 32); if (atsha204_send_cmd(nonce_cmd, 34) != 0) return 1; atsha204_delay_ms(5); /* 等芯片内部完成 Nonce 处理 */ /* 第二步:发 Digest 命令,指定用哪个 Slot 的密钥 */ digest_cmd[2] = 0x00; /* Slot 0 */ digest_cmd[3] = 0x00; if (atsha204_send_cmd(digest_cmd, 4) != 0) return 2; /* 返回的 32 字节就是摘要 */ if (atsha204_recv_resp(response, 32) != 0) return 3; return 0; }nonce_cmd[1]是模式选择,0x00表示挑战直接由主机传入,0x03表示让芯片自己生成随机数当挑战。digest_cmd[2]和digest_cmd[3]拼起来是 Slot 编号,这里用的是 Slot 0。实际项目里密钥通常放在 Slot 0 或 Slot 1,具体看你的配置。延时那 5 毫秒不能省,芯片内部做 SHA-256 需要时间,发太快会读到旧数据。
2.3 和 STM32 的对接方式
ATSHA204 支持 I2C 和单总线两种接口,STM32 例程里用的是 I2C。接线就四根:VCC、GND、SDA、SCL,SDA 和 SCL 各接一个 4.7K 上拉电阻到 3.3V。从机地址默认是0xC8(8 位写地址),有些封装是0xCA,这个在手册的“设备寻址”一节有说明。
STM32 这边用标准外设库或者 HAL 库的 I2C 都行,例程里一般会封装一层atsha204_i2c_read/write,把底层收发和芯片的时序要求隔离开。芯片对时序有一定要求,比如命令之间要有tWW等待时间,连续发命令太快会失败。这些延时参数在手册的“时序特性”表里,例程里通常用delay_ms或delay_us实现。
3. 例程跑通实录:从工程导入到读到序列号
3.1 工程结构和依赖
这份 STM32 例程的目录结构大致是这样的:Drivers/下放 STM32 的 HAL 库和 CMSIS,ATSHA204/下放芯片驱动,包括atsha204.c、atsha204.h、atsha204_i2c.c和配置文件atsha204_config.h,User/下是main.c和业务逻辑。如果你用的是 Keil,直接打开.uvprojx就能编译;如果是 IAR 或者 STM32CubeIDE,需要把源文件加进工程,注意头文件路径要包含ATSHA204/目录。
依赖上,例程只用了 STM32 的 I2C 外设和 GPIO,没有额外的中间件。atsha204_config.h里定义了几个关键宏:ATSHA204_I2C_ADDR是从机地址,ATSHA204_SLOT_USED是默认使用的 Slot 编号,ATSHA204_USE_SOFT_I2C可以切换硬件 I2C 和软件模拟 I2C。如果你的板子 I2C 引脚被占了,把ATSHA204_USE_SOFT_I2C打开,用任意两个 GPIO 就能跑。
3.2 编译前必须改的三个地方
第一个是 I2C 从机地址。例程默认0xC8,但如果你买的是带 ATSHA204A 的模块,地址可能是0xC8也可能是0xCA,用逻辑分析仪抓一下最稳。第二个是 Slot 编号,例程默认用 Slot 0,如果你的密钥已经写在别的 Slot,要改ATSHA204_SLOT_USED。第三个是延时函数,例程里用的是 HAL 的HAL_Delay,如果你的工程里没初始化 SysTick,要换成自己的延时实现。
/* atsha204_config.h 里需要按实际硬件改的宏 */ #define ATSHA204_I2C_ADDR 0xC8 /* 从机地址,常见 0xC8 或 0xCA */ #define ATSHA204_SLOT_USED 0x00 /* 默认使用的密钥 Slot */ #define ATSHA204_USE_SOFT_I2C 0 /* 1 表示用软件 I2C */ #define ATSHA204_I2C_TIMEOUT 100 /* I2C 超时,单位 ms */改完这三个宏,编译烧录,串口应该能打印出芯片的序列号。如果串口没输出,先确认printf重定向有没有配好,这个和 ATSHA204 本身无关,但新手经常在这里卡住。
3.3 用串口验证读序列号
例程的main里一般会先初始化 I2C,然后调用atsha204_read_sn,把读到的 4 字节序列号通过串口打印。序列号是芯片出厂时固化的,每颗都不一样,读到它说明 I2C 通信链路已经通了。如果读回来全是0xFF,大概率是上拉电阻没接或者从机地址错了;如果全是0x00,检查供电,芯片没起来。
int main(void) { uint8_t sn[4] = {0}; uint8_t ret; HAL_Init(); SystemClock_Config(); MX_I2C1_Init(); /* 初始化 I2C1 */ MX_USART1_UART_Init(); /* 初始化串口,用于打印 */ ret = atsha204_read_sn(sn); if (ret == 0) { printf("SN: %02X %02X %02X %02X\r\n", sn[0], sn[1], sn[2], sn[3]); } else { printf("read sn failed, code=%d\r\n", ret); } while (1) { /* 主循环 */ } }这段代码里ret的返回值对应不同的失败原因,1是发送失败,2是接收失败。调试时先看返回值,比盲目抓波形快。序列号读通之后,再往下做挑战应答就有底了。
4. 避坑与排查:I2C 通信和配置区的五个常见问题
4.1 读回来全是 0xFF 或 0x00
现象是串口打印的序列号全是0xFF或者全是0x00。原因通常是三类:上拉电阻缺失或阻值不对、从机地址配错、供电电压不对。ATSHA204 的工作电压是 2.0V 到 5.5V,但 I2C 电平要跟主控匹配,3.3V 主控配 3.3V 供电最稳。解决方法是先用万用表量 SDA 和 SCL 的静态电平,正常应该是高电平;再用逻辑分析仪抓一次读序列号的波形,看从机有没有 ACK。如果从机不 ACK,基本就是地址或供电问题。
4.2 挑战应答返回状态字 0x01
现象是 Digest 命令返回的状态字是0x01,表示命令执行失败。原因一般是 Slot 没有配置成允许 Digest 使用,或者 Nonce 命令没有先执行。ATSHA204 的 Digest 命令依赖前一步的 Nonce 结果,顺序不能反。解决方法是检查配置区里对应 Slot 的IsSecret和WriteConfig位,确认这个 Slot 被配置成了密钥槽而不是普通数据槽。如果配置区已经锁了,那就只能换一颗芯片重新配置。
4.3 连续发命令导致超时
现象是单次读序列号正常,但连续做挑战应答时第二次或第三次就失败。原因是芯片内部处理 SHA-256 需要时间,命令之间要留够tWW等待。手册里tWW典型值是 5 到 10 毫秒,具体看命令类型。解决方法是在每次发命令前加delay_ms(5)或更长,或者在驱动里封装一个atsha204_wait_ready,轮询状态直到芯片空闲。
4.4 配置区被锁后无法修改
现象是执行 Lock 命令之后,再想改 Slot 权限就返回错误。原因是配置区锁定是永久性的,锁了就不能改。这是芯片的安全设计,不是 bug。解决方法是在锁定之前,把配置区的每一个字节都确认好,最好先用一颗样片做完整验证,确认无误再批量锁定。我一般会在代码里加一个ATSHA204_ALLOW_LOCK宏,默认关闭,只有量产固件才打开。
4.5 软件 I2C 时序不匹配
现象是硬件 I2C 能通,切到软件 I2C 就失败。原因是软件 I2C 的延时和芯片时序要求不匹配,太快或太慢都会导致采样错误。解决方法是根据主频调整delay_us的参数,用逻辑分析仪看 SCL 频率,控制在 100kHz 左右比较稳。ATSHA204 支持标准模式和快速模式,但软件模拟时建议先用 100kHz 跑通再提速。
5. 二次开发:把例程改成自己的认证方案
5.1 密钥写入和 Slot 规划
例程默认只读序列号,实际项目里第一步是把密钥写进 Slot。写密钥用 Write 命令,但要注意:如果配置区已经锁了,且 Slot 配置成不可写,那就写不进去了。所以正确的顺序是:先写配置区、再写密钥、最后 Lock。密钥写入时,数据要按 32 字节对齐,不足的补零。
/* 向指定 Slot 写入 32 字节密钥 */ uint8_t atsha204_write_key(uint8_t slot, uint8_t *key) { uint8_t cmd[36]; cmd[0] = 0x12; /* Write 命令 */ cmd[1] = 0x00; /* 写数据区 */ cmd[2] = slot; /* Slot 编号 */ cmd[3] = 0x00; memcpy(&cmd[4], key, 32); if (atsha204_send_cmd(cmd, 36) != 0) return 1; atsha204_delay_ms(10); /* 写操作需要更长的等待 */ return 0; }cmd[1]是写模式,0x00表示写数据区,0x80表示写配置区。写配置区更危险,因为一旦写错可能直接锁死,建议先用atsha204_read_config把当前配置读出来备份。
5.2 主机侧摘要比对
芯片返回摘要后,主机要自己算一遍做比对。STM32 上可以用软件 SHA-256 库,也可以用带硬件加密的型号。比对逻辑很简单:主机用同样的密钥和挑战算 SHA-256,和芯片返回的 32 字节逐字节比较。一致就通过,不一致就拒绝。
/* 主机侧验证芯片返回的摘要 */ uint8_t atsha204_verify(uint8_t *challenge, uint8_t *chip_resp, uint8_t *host_key) { uint8_t host_digest[32]; /* 用软件 SHA-256 算主机侧摘要 */ sha256_compute(host_key, 32, challenge, 32, host_digest); /* 逐字节比对 */ if (memcmp(host_digest, chip_resp, 32) == 0) { return 0; /* 认证通过 */ } return 1; /* 认证失败 */ }这里sha256_compute的入参顺序要和芯片内部一致,通常是“密钥 + 挑战”或者“挑战 + 密钥”,具体看芯片配置。这个顺序在手册的“Digest 命令”一节有说明,搞反了摘要永远对不上。
5.3 量产时的配置固化流程
量产时不能每颗芯片都手动配,要把配置和密钥写入做成自动化流程。我一般会写一个产测工具,通过串口或 I2C 批量操作:先读序列号记录,再写配置区,再写密钥,最后 Lock,每一步都校验返回值。配置区的内容可以存在一个二进制文件里,产测工具直接读文件写入,避免手敲出错。
| 步骤 | 操作 | 校验方式 |
|---|---|---|
| 1 | 读序列号 | 确认非 0xFF |
| 2 | 写配置区 | 回读比对 |
| 3 | 写密钥 | 回读比对(如果 Slot 可读) |
| 4 | Lock 配置区 | 确认 Lock 状态位 |
| 5 | 挑战应答自测 | 主机比对通过 |
这张表里的每一步都要有失败重试和日志,量产时最怕的是某颗芯片写了一半失败,流到下一站才发现。产测工具里加一个“已锁定”标记,锁过的芯片不再重复操作。
5.4 一个容易忽略的细节
最后说一个我踩过的坑:ATSHA204 的 I2C 地址在读写时是不一样的,写地址是0xC8,读地址是0xC9。有些 HAL 库的HAL_I2C_Master_Transmit需要传 8 位地址,有些需要传 7 位地址左移一位,这个在移植例程时特别容易翻车。我现在的习惯是,拿到任何一颗 I2C 芯片,先用逻辑分析仪抓一次标准读写波形,确认地址和时序都对得上,再往工程里集成。从那以后我每次移植新的 I2C 驱动,都强制走一遍“抓波形 → 对地址 → 读 ID”的流程,省下来的调试时间比抓波形那几分钟多得多。希望这份手册和例程能帮你把 ATSHA204 顺利跑起来。
本文还有配套的精品资源,点击获取