Replay attack概念
Replay attack是指攻击者发送一个目的主机已经接受过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性,replay attack可以由发起者,也可以由拦截并重发
该数据的敌方进行。攻击者可以利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。重放攻击在任何通信过程中都可能发生,是黑客常用的攻击方式之一。
原理:replay attack的基本原理就是把以前窃听到的数据原封不动的发送给接收方。很多时候,网络上传输的数据是加密过的,此时窃听者无法得到数据的准确意思,但是如果他知道这些数据的作用,就可以在不知道数据内容的情况下通过再次发送这些数据达到愚弄接受端的目的。例如有的系统会将鉴别信息进行简单加密后进行传输,这是攻击者虽然无法窃听密码,但是他们却可以首先截取加密后的口令然后将其重发,从而利用这种方式进行有效的攻击。再比如假设网上存款系统中,一条消息表示用户支取的一笔存款,攻击者完全可以多次发送本条消息从而窃取。
举例来说:
A向B请求服务(比如登陆某个网站),A将密码hash传给B。但是在这中间,E抓取到该hash值。此后,E冒充A向B发送同样的hash值来获取服务。
针对这种情况引入了Replay protected机制
实现方式包含但不限于以下几种方式
- 随机数
- 时间戳
- 流水号
- 一次性口令
在emmc的RPMB区域,就使用了随机数+流水号的方法
RPMB的一些应用场景
场景一:实现eMMC和SoC的绑定;
场景二:存储手机IMME号
场景三:存储敏感密码,比如指纹信息,用于防盗等。
RPMB分区 Replay Protect 原理
基本概念
使用eMMC的产品,在生产线生产时,会为每一个产品分配一个唯一的256bits的Secure Key,烧写到eMMC的OTP(只能烧写一次的区域),同时Host在安全区域中(例如:TEE)也会保留该Secure Key。
在eMMC内部,还维护着一个RPMB Write Counter变量。RPMB没进行一次合法的写入操作,该值就会自动加一
通过Secure Key和Write Counter的应用,RPMB可以实现数据读取和写入的Replay Protect。
数据访问帧格式![](https://i-blog.csdnimg.cn/direct/fdc1b9dbdc274ae5be15962a511a0d15.png)
分字段解释
1.Req/Resp
Legth:2Byte
Direction: Request (to the memory), Response (from the memory)
Description:定义去往或来自存储器的请求和应答类型。下表列出了所定义的请求和应答。应答类型对应于之前的重发保护存储块读写请求。
- Key/MAC
Length:32byte(256bit)
Direction:Request(key或者MAC),Response(MAC)
Description::认证密钥或消息认证码(MAC)取决于请求/应答类型。 MAC 将在最后(或唯 一)数据块中提交
- Operation Result
Length:2Byte
Direction:reponse
Description:包括写计数器状态(有效、溢出)和对重发保护存储块访问是否成功。下表列出了定义的结果和可能失败原因。
- write Counter
Length:4Byte
Direction:Request and Response
Description:主机发出的成功的认证数据写入请求和认证设备配置写入请求总数的计数器值。
- Data Address
Length:2Byte
Direction:Request and Response
Description:要对重发保护存储块编程或读取的数据地址。地址是所访问的半扇区(256B)
的序号。在 CMD18 和 CMD25 中的地址参数被忽略。
- Nonce
Length:16Byte
Direction:Request and Response
Description:主机为请求生成的随机数,由 e-MMC 重发保护存储块引擎复制到应答。
- Data
Length:256Byte
Direction:Request and Response
Description:只能通过成功认证读写访问的数据。数据可被主机重写,但不能擦除
- Block Count
Length:2Byte
Direction:request
Description:请求读取/编程的块数(半扇区,256B)。此值等于CMD23参数中的计数值。
RPMB内存分區
Replay Protected Memory Block 包括以下寄存器和内存分区:
1.Authentication Key
Size:32byte
Type:Write once
Description:一次编程认证密钥寄存器。此寄存器不能重写,擦除或读取。此密钥由 e-MMC
重发保护存储块引擎在认证访问时用于计算 MAC。
2.Write Counter
Size:4Byte
Type:Read only
Description:主机发出的成功经过身份验证的数据写入请求和经过身份验证的设备配置写入请求总数的计数器值。e•MMC生产后的初始值为0x0000 0000。值将通过e•MMC 重放保护内存块引擎自动递增1,同时成功进行编程访问。无法重置该值。计数器0xFFFF FFFF达到最大值后,它将不再递增(防止溢出),并且操作结果值中的位[7]将被永久设置。
- Data
Size: 128kB min (RPMB_SIZE_MULT x 128kB)
Type: Read/Write
Description:只能通过成功认证读写访问的数据。数据可被主机重写,但不能擦除。
MAC计算
消息认证码(MAC)使用HMAC SHA-256计算,如[HMAC-SHA]所定义。HMAC SHA-256计算将一个密钥和一个消息作为输入。计算出的MAC是256 位(32Byte,作为请求或响应的一部分被嵌入到数据帧中。
用于MAC计算的key始终存储在emmc中,也是32字节。用作MAC计算输入的信息是数据帧中字段的连接,其中不包括 stuff bytes, the MAC itself, start bit, CRC16, and end bit。也就是说,MAC是按照数据帧中bytes[283:0]中的顺序来计算的。
在请求或者响应中,如果有很多个数据包被发送,那么这些数据包的bytes [283:0]按照发送的循序拼接一起,然后作为MAC计算的输入信息。MAC只会放在最后一个数据包中。
举例来说:
假设write counter是0x12345678。host想要在0x0010这个地址上写512个字节,那么就要组成两个数据包。假定前一个数据包中256个字节的data是0xAA,后一个数据包中的256个字节是0xBB,MAC只会放在最后第二个数据包中,如图:
通过以下信息计算出MAC;
RPMB的数据读取命令流向
数据读取
1、Host 向 eMMC 发起读 RPMB 的请求,同时生成一个 16 bytes 的随机数,发送给 eMMC。
2、eMMC 将请求的数据从 RPMB 中读出,并使用 Secure Key 通过 HMAC SHA-256 算法,计算读取到的数据和接收到的随机数拼接到一起后的签名。然后,eMMC 将读取到的数据、接收到的随机数、计算得到的签名一并发送给 Host。
3、Host 接收到 RPMB 的数据、随机数以及签名后,首先比较随机数是否与自己发送的一致,如果一致,再用同样的 Secure Key 通过 HMAC SHA-256 算法对数据和随机数组合到一起进行签名,如果签名与 eMMC 发送的签名是一致的,那么就可以确定该数据是从 RPMB 中读取到的正确数据,而不是攻击者伪造的数据。
数据写入
1、Host 按照上面的读数据流程,读取 RPMB 的 Write Counter(通过Write Counter来识别数据的有效性)。
2、 Host 将需要写入的数据和 Write Counter 拼接到一起并计算签名,然后将数据、Write Counter 以及签名一并发给 eMMC。
3、eMMC 接收到数据后,先对比 Write Counter 是否与当前的值相同,如果相同那么再对数据和 Write Counter 的组合进行签名,然后和 Host 发送过来的签名进行比较,如果签名相同则鉴权通过,将数据写入到 RPMB 中。
(UFS的RPMB和emmc的原理相同)
访问RPMB分区
ecsd[179]设置PARTITION_ACCESS后,就可以进行多块读写(CMD23/CMD18/CMD25)了。
在Authenticated Write的时候,任何未定义的命令参数、序列以及高优先级的中断,都会导致访问失败。
认证秘钥编程 Programming of the Authentication Key
- 秘钥编程
- 认证秘钥用多块写CMD25命令发送,即发送一个512Bit的数据包给eMMC。数据包的第[1:0]=0x0001;[315:284]=KEY
- 在CMD25之前,应该将CMD23的bit31(Reliable Write Request )置1,同时将块数也置1(CMD arg:0x80000001),否则后续的多块写命令必然会失败。并指示一般错误。
- eMMC在发送CMD25包数据的CRC状态之后,DAT0线上的忙信号指示忙于秘钥编程。该状态可用CMD13轮询,所接收到的状态应该包括通用状态条件,不包括秘钥编程成功的状态。
时序分析:
1.CMD23
2.CMD25
- 如何判断刚才的秘钥编程是否成功
先通过cmd25发送一个512b的包,然后再用CMD18读取。
发送读取秘钥编程结果的请求包:
- 通过CMD25发送一个同样格式的512B的包,数据包[1:0]=0x005
- 发送之前,CMD23要设置块数为1块(CMD23 arg = 0X00000001),否则后续的多块写命令必然会失败。并指示一般错误
- e-MMC 在 CRC 状态之后 DAT0 线上的忙信令表示请求忙。
读取秘钥编程的结果:
- 通过CMD23+CMD18进行秘钥编程的结果。结果也是封装在512Bit的数据包中的。
- 在发送CMD18之前,CMD23要设置块数为1块(CMD23 arg = 0x00000001),否则后续的多块读命令必然会失败。并指示一般错误
- 读出来的数据包类型Byte[1:0]为0x0100,和秘钥编程的请求数据类型对齐。
- 如果数据包中的Byte[3:2]是如下值,则代表不同的含义:
如果认证密钥还没有编程,则结果域返回0x07(认证密钥还未编程)
如果密钥编程失败则返回结果0x05(写失败)
如果在认证密钥编程中发生了其他错误,则返回结果0x01(一般错误)
时序分析:
CMD25 (REQ= 0x0005)
CMD18(返回结果)
- 注意
- 密钥key是host自己随便定义的,通过密钥编程来给emmc写入这个key。这个key就一直存在在emmc内部,不会再改变了,除非重新开卡。这个key只需要配置一次,之后进行数据读写就不用再进行秘钥编程这一步了。它的原理是host会通过key数据生成mac,放在byte[283:28],emmc收到数据包之后,就会根据之前秘钥编程写入的key和数据也生成一个mac,和接受到的mac对比,即可。
计数器的读取Reading of the Counter Value
计数器的读取也是先用CMD25发送一个包,再用CMD18进行读取。
- 发送读取计数器的数据包
- 在CMD25命令之前,用CMD23将块计数设置为1(CMD23 arg = 0x00000001)。如果块计数没有设置为1,则后续的多块读命令必然失败,并指示一般错误
- 包中包含请求类型([1:0]=0x0002)和随机数
- 在CRC状态之后由eMMC发出的DAT0上的忙信号表示忙。
- 读取计数器值
- 在 CMD18 命令之前,用 CMD23 将块计数设置成 1(CMD23 arg = 0X00000001)。如果块计数没有设置成 1,则后续的读多块命令必然失败,并指示一般错误。
- 读取到的包中包含应答类型信息、请求中接收到的随机数的副本、写计数器值、MAC 和操作结果。
- 如果数据包中的结果byte[3:2]是如下值,则代表不同的含义:
- 如果读计数器值失败,则返回的结果是 0x06(读失败)。
- 如果发生了其他一些错误,则结果是 0x01(一般错误)。
- 如果计数器過期,返回结果的 bit 7 还要置为 1(结果值分别为 0x80、0x86 和 0x81)
时序分析:
CMD25
CMD18
认证数据写Authenticated Data Write
(1)认证数据写
1)在CMD25之前,应该将CMD23的bit31置一,块计数是要编程的半扇区的数目(256B),否则后续的多块写命令必然会失败,并指示一般错误。
2)数据包512B,其中byte[283:28]是存放写数据的,也就是要写入到eMMC的数据,会以半扇区计算。
3)数据包中包含请求类型信息,块计数,计数器值,数据的起始地址,数据本身和MAC。
4)在多块写情况下,MAC只包含在最后的(第n个)包中,其他的n-1个包中存放MAC的位置只包含0x00。
5)在每一个包中,地址都是整个访问的其实地址(不是各个半扇区的地址),块计数是半扇区的总数(不是半扇区的序号)
6)包的请求类型byte[1:0]=0x0003
7)eMMC在放CMD35包数据的CRC状态之后,DAT0线上的忙信号表示忙于秘钥编程,该状态可用CMD13轮询,所接收到的状态应答包含通用状态条件,不包含写成功的状态。
8)单次CMD25命令最多写数据的大小取决于EN_RPMB_REL_WR(EXT_CSD[166]bit4)以及EXT_CSD_REV[192]。
①当emmc是ecsd[192]为8,也就是emmc为V5.1版本:
当EN_RPMB_REL_WR=0,CMD25可以带一个包,也就是在emmc内部写入256B的数据,或者带2个包,在emmc内部写入一个sector(512B)的数据。
当EN_RPMB_REL_WR=1,CMD25可以带一个包,也就是在emmc内部写入256B的数据,或者带2个包,emmc内部写入一个sector(512B)的数据,还可以带32个包,也就是在emmc内部写入8K的数据。
②当emmc ecsd[192]为7,也就是emmc为V5.0版本:
CMD25最多支持携带两个包,也就是写入emmc的数据为512B。
③当emmc ecsd[192]为5或6时,也就是emmc为V4.41/4.51/4.5版本:
CMD25最多支持携带包的个数为:ecsd[222] * 2个
9)如果CMD25单次带的包个数不是上述定义的,写失败,并会报一般错误
(2)eMMC接受到数据后,会进行怎样的判断?
1)eMMC接受到消息后,它首先检查计数器是否溢出,如果写计数器溢出,则eMMC设置结果为0x85(写失败且写计数器溢出)。数据不写入eMMC。
2)接下来检查地址。如果地址有错误(超范围),则结果置为0x04(地址错误)
3)如果写计数器没有溢出,则eMMC计算请求类型,块计数,写计数器,地址和数据的MAC,并与请求中的MAC比较。如果MAC不同,则eMMC设置结果为0x02(认证失败)。数据不写入eMMC。
4)如果请求中的MAC与计算的MAC相等,则eMMC将请求中的写计数器和eMMC中存储的写计数器比较,如果两个计数器不同,则eMMC设置结果为0x03(计数器错误)。数据不写入eMMC。
5)如果MAC和写计数器比较成功,则写请求认为是通过认证的。请求中的数据被写入请求中所指示的地址,写计数器+1.如果写失败则返回结果0x05(写失败)。如果写过程中出现了其他的错误,则返回错误0x01(通用错误)。
(3)判断认证数据编程写是否成功
同样,先通过CMD25,发送一个512B的数据请求包。然后通过CMD18读取
发送读取认证写结果的请求包
1)在CMD25之前,要通过CMD23将块计数设置为1(CMD23 arg = 0x00000001)。如果块计数没有设置为1则后续的多块写命令必然失败,并且只是一般错误。
2)包大小是512B,包含请求信息,请求类型byte[1:0]= 0x0005表示寄存器读请求。
3)CRC状态之后,由eMMC在DAT0线上发出的忙信号表示请求忙。
读取认证数据写的结果:
1)在读命令之前,用 CMD23 将块计数设置为 1。如果块计数没有设置成 1(CMD23 arg = 0X00000001),则后续的读多块命令必然失败,并指示一般错误。
2)包大小是 512B,包含应答类型信息、递增后的计数器值、数据地址、MAC 和编程操作的结果。
时序分析:
1.单块写(发256byte数据)
CMD25发写请求
CMD25发读取结果请求
CMD18读取写的结果
2.多块写(发512byte数据)
1.读计数器值
2.写数据
3.读取写结果
认证数据读Authenticated Data Read
通过认证数据读,也是先通过CMD25发送一个512B的数据请求包,然后再通过CMD18进行读数据。
(1)发送数据包
1)在 CMD25 之前,通过 CMD23 设置块计数为 1。如果块计数没有设置成 1(CMD23 arg = 0X00000001),否则后续的写多块命令必然失败,并指示为一般错误。
2)包大小是 512B,包含请求类型信息、随机数和数据地址。请求类型byte[1:0] = 0x0004 表示数据读请求。
3) CRC 状态之后,由 e-MMC 在 DAT0 线上发出的忙信令表示请求忙。
(2)emmc收到数据包后会进行什么操作?
1)当 eMMC 接收到此请求时,它首先检查地址。如果地址有错误则结果设置为 0x04(地址错误)。数据读无效。
2)在成功地提取数据后,从应答类型、随机数、地址、数据和结果计算 MAC。如果 MAC 计算失败则返回结果 0x02(认证失败)。
- 认证数据读
1)在读命令之前,用 CMD23 设置块计数。块计数是要读取的半扇区的个数。如果块计数没有设置,则后续的读多块命令必然失败,并指示一般错误。(比如,正常读取4个LBA的数据,但是实际上需要设置8个块数)数据本身是用读取多块命令 CMD18 读出的。
2)包大小是 512B,包含应答类型信息、块计数、在请求中接收到的随机数的副本、数据地址、数据本身、MAC 和结果。
3)在多块情况下,MAC 只包含在最后的包 n 中,其他的n-1 个包将包含 0x00。
4)在每一个包中,地址都是整个访问的起始地址(不是各个半扇区的地址),而且块计数是半扇区的总数(不是半扇区的序号)。
5)如果从 eMMC 内地址单元提取数据失败,则返回的结果是 0x06(读取失败)。
如果在读取过程中发生了其他一些错误,则返回错误是 0x01(一般错误)。
时序分析:
CMD25发送读请求
CMD18读回数据
读回的数据
Authenticated Device Configuration Write
为什么认证设备构造读写和写保护有关?
安全写保护相关寄存器
主机应通过将SECURE_WP_MODE_CONFIG中的SECURE_WP_EN字段设置为0x1来进入安全写保护模式。
如果主机进入安全写保护模式,则仅当SECURE_WP_MASK设置为0x1时,才会更新与
USER_WP [171],BOOT_WP [173],TMP_WRITE_PROTECT [12]和PERM_WRITE_PROTECT [13]等写保护相关的字段。
其中当SECURE_WP_EN为0:非安全写保护模式。eCSD和CSD里面的内容为正常写保护的东西。相关寄存器值可以通过CMD6或者CMD27来改变。
SECURE_WP_EN为1:安全写保护模式。安全写保护模式下不能修改ecsd或者csd的值。如果非要修改呢?能不能修改取决于SECURE_WP_MASK时候设置的值。
如果主机希望设备进入安全写保护模式,主机需用通过Authenticated Device Configuration Write来将SECURE_WP_EN置1.(对应数据帧address传0x0001)
host同时也可以通过Authenticated Device Configuration Read将该寄存器的值读取出来。
与此同时SECURE_WP_MODE_CONFIG的bit0为SECURE_WP_MASK。修改该寄存器的内容,也需要通过Authenticated Device Configuration Write来修改。(对应数据帧address传0x0002)
(1)写认证设备配置
1)在CMD25之前,应该将CMD23的bit31置1,同时将块数也需要设置为1(CMD23的arg = 0X80000001),否则后续的多块写命令必然会失败。并在操作结果中指示一般错误(0x0001)。
2)包的大小为512B。包含请求类型信息、块的个数、计数器的值、数据开始地址、数据本身、MAC。
3)请求类型byte[1:0] = 0x0006
4)数据地址是被更新过的设备构造寄存器的地址,0x0001或0x0002
5)eMMC在发送CMD25包数据的CRC状态之后,DAT0线上的忙信号表示忙于编程状态也可用CMD13 轮询。所接收到的状态应答包括通用状态条件,不包括成功编程的状态。
6)如果host访问保留区域(address[0和address[3-255]]),设备不会返回error,但是数据不会写入eMMC。
(2)emmc接收到数据后,会进行怎样的判断?
1)eMMC接受到消息之后,首先检查计数器是否溢出。如果写计数器溢出,则eMMC设置结果为0x85(写失败且写计数器溢出)。数据不写入eMMC。
2)如果计数器没有溢出,根据包的byte[283:0]重新计算MAC,并和请求时候的MAC进行比较,如果不同,则结果为0x02(认证失败)。数据不写入 e-MMC。
3)如果MAC值相同,比较写计数器,如果不同,则结果为0x03(计数器错误)。数据不写入 e-MMC。
4)如果MAC和计数器比较都相同,那么写请求将会被考虑进行认证。写请求中的数据将会根据写请求中的地址,将数据写入到 Device Configuration Area。写计数器加1。
5)如果写失败,结果为0x05(写失败)。如果写过程中有其他的错误出现,结果为0x01(通用错误)
(3)认证设备配置写是否成功
同样,先通过CMD25,发送一个512B的数据包。然后通过CMD18读取。
发送读取设备构造写结果的请求包:
1)在 CMD25 之前,通过 CMD23 设置块计数为 1。如果块计数没有设置成 1(CMD23 arg = 0X00000001),则后续的写多块命令必然失败,并指示为一般错误。
2)数据包的第[1:0]=0X0005;表明要读取认证设备构造写的结果。
3)包中包含请求类型信息。
4)e-MMC在发送CMD25包数据的CRC 状态之后,DAT0 线上的忙信令表示忙于请求。
5)Authenticated Device Configuration write response的响应类型为0x0600.
认证设备结构写结果读取:
1)发CMD18之前,需要发CMD23,这只块数为1(CMD23 arg = 0X00000001),否则后续的写多块命令必然失败,并指示为一般错误。
2)读取到的512B的包包含 the response type information, the incremented counter value, index for Device Configuration Area -, the MAC and result of the data programming operation.
Authenticated Device Configuration Read
认证设备构造读和写保护有关。
先通过CMD25发送一个包,之后CMD18进行数据读取。
(1)发送认证设备构造读所需要的包
1)发CMD25之前,需要发CMD23,设置块数为1(CMD23 arg = 0X00000001),否则后续的写多块命令必然失败,并在result[3:2]中指示为一般错误。
2)包的大小为512B。包含随机数和请求类型(byte[1:0] = 0x0007)。
3)e-MMC在发送CMD25包数据的CRC 状态之后,DAT0 线上的忙信令表示忙于请求。
(2)认证设备构造读
1)发CMD18之前的CMD23需要将块数设置为1(CMD23 arg = 0X00000001),否则后续的多块读命令必然失败,并在result[3:2]中指示为一般错误。
2)读取到的512B的包中 包含请求数据类型,块数, 随机数(同请求数据帧一样), 数据地址, MAC,result。
3)如果响应结果为0x06,说明读取失败
如果响应结果为0x01,说明有其他的错误出现。
7 计算RPMB的区块大小
RPMB_SIZE_MULT [168]
RPMB 分区长度 = 128kB x RPMB_SIZE_MULT
RPMB区域最大为16M。
8 其他规则
1、重新开卡后RPMB的Write Counter被清零。
2、由ecsd[166]可以知道,RPMB每次只能写256B(single 512B frame)、512B(2个512B frame)、8KB(32个512B frames),也就是说每次只能写1个、2个、32个sector。
3、每次往RPMB写入一个sector,也即是256B,可以假设RPMB区域一个sector为256个字节。或者假设flash层一个sector还是512个sector,不过经过控制器或者firmware后,编了一个号,一个实际的sector中前256B的地址为1,后256B的地址为2.可以这么理解。
4、RPMB区域不支持擦除操作。
5、boot和RPMB区域的数据,就算打开cache,也不经过cache,直接写入到flash中。