当你辛辛苦苦开发了一个方案,正准备享受你的劳动果实时,突然一个晴天霹雳,发现被盗版了。。。 财富毫不留情的离你而去。只剩你在风中瑟瑟发抖。
未避免让您冻感冒了,我这里提供一个防盗版思路,抛转引玉,探讨探讨。
一般我们通常所说的加密,防盗版,主要是指两件事:
1,防复制,你的镜像一般都是烧录在flash里,如果flash对拷就实现盗版,那么就相当于你直接在大街上裸奔。
2,防逆向,虽然源码见不着,但二进制跟源码也没太大区别,仅仅可读性差了点,但真要去读,还是可以读懂的。别人读懂了,就什么事都可能发生,爆破,仿制,扣出核心算法,等等。
为解决这两件事,我们先来一件一件分析。
第一件事,防复制,避免flash对拷盗版,这个可以通过绑定机器唯一序列号,唯一序列号的来源,CPUID最优,其次时候FLASH ID或其他芯片的ID。具体怎么绑定,就是引入SHA256算法,下面讨论。
第二件事,防逆向,我们就需要对镜像进行加密了,在运行时解密,这里引入AES256对称加密算法。
光引入这两个算法,还是不够的,还有一个完整性检验,用于防爆破,这里引入ECSDA256签名校验算法。
先总结下,防盗版,就是需要,在保护镜像的完整性的同时,一机一加密镜像,只要能做到防逆向,防修改,硬件绑定,这三个特性,你的财富就不会离你而去的。
先说个前提,如果需要做到这三个特性,唯一可靠的实现是要求芯片支持加密引导,如果不支持,这三点是不可能完全做到的。
虽然完全做不到,但实现大部分保护,还是有可能的。
下面的实现,认为芯片是支持加密引导的,且芯片没办法复制,里面的key也是安全的。这是前提。
离线
现在祭出方案,来一个核心头信息
struct zdesc_t { /* Total 256 bytes */
uint8_t magic[4]; /* ZB??, I for bind id, E for encrypt image */
uint8_t key[32]; /* Aes256 encrypt key (hardcode or efuse suggested) */
uint8_t sha256[32]; /* Sha256 hash */
uint8_t signature[64]; /* Ecdsa256 signature of sha256 */
uint8_t csize[4]; /* Compress size of image */
uint8_t dsize[4]; /* Decompress size of image */
uint8_t public[33]; /* Ecdsa256 public key (hardcode suggested) */
uint8_t majoy; /* Majoy version */
uint8_t minior; /* Minior version */
uint8_t patch; /* Patch version */
uint8_t message[80]; /* Message additionally */
};
离线
先说下,采用到的相关技术,LZ4压缩,SHA256算法,AES256算法,ECSDA256算法。
离线
制作镜像简略流程:
LZ4压缩二进制镜像 ->AES256加密LZ4压缩镜像 -> SHA256计算摘要含头信息 -> ECSDA256对SHA256摘要进行签名 -> 更新头信息 -> AES256加密头信息
运行镜像流程
读取头信息 -> AES256解密头信息 -> 验证SHA256签名 -> 校验SHA256运算结果 -> AES256解密镜像 -> LZ4解压镜像
离线
struct zdesc_t { /* Total 256 bytes */
uint8_t magic[4]; /* ZB??, I for bind id, E for encrypt image */
uint8_t key[32]; /* Aes256 encrypt key (hardcode or efuse suggested) */
uint8_t sha256[32]; /* Sha256 hash */
uint8_t signature[64]; /* Ecdsa256 signature of sha256 */
uint8_t csize[4]; /* Compress size of image */
uint8_t dsize[4]; /* Decompress size of image */
uint8_t public[33]; /* Ecdsa256 public key (hardcode suggested) */
uint8_t majoy; /* Majoy version */
uint8_t minior; /* Minior version */
uint8_t patch; /* Patch version */
uint8_t message[80]; /* Message additionally */
};
这个里面有两个东西涉及到安全性:
最关键的是AES256的密钥,这个需要防泄漏,最好是芯片只带AES256硬件压缩,KEY是只写的,这种安全性最高,基本很难获取key,这里技巧,根密钥是只写的,然后镜像采用的密钥不是根密钥,而是由根密钥经过运算生成的次级密钥,避免根密钥直接暴露。如果没有硬件AES256,那么这个key就只能硬编码到代码里,当然硬编码到代码里,还是有可能被找出来的,可以适当的用其他算法保护下这个key,比如RC4这种算法来保护key,安全性最差的,就是key直接放在头里,这个一般不建议,知道文件结构后,很容易获取。
其次是ECDSA256签名的公钥,其实这个公开是没有任何问题的,关键的是如果AES KEY被破了后,怎么防止伪造签名的问题,破解者伪造签名,唯一的思路就是自己生成一对ECDSA256密钥对,替换默认的,要应对这个,就是公钥不能直接采用文件头里的公钥,而是直接硬编码到代码里,当然硬编码到代码里,也是有可能被修改的,毕竟最关键的AES KEY 已经被破了。伪造签名,仅仅难度增加而已不能测地杜绝。
总结,这里最关键的是AES256 KEY,如果这个KEY被泄漏了,整套系统就失效了,如果KEY没有泄漏,那么整套系统就完全安全的。
如何将AES key泄漏的风险降到最低呢。就是一台机器,一个次级AES KEY,当然每个芯片的根密钥都是一样的,仅仅次级密钥是由根密钥和硬件ID通过某种算法生成的。及时破解了这台机器的AES key,也是没有太大价值的。
一句话,根密钥要好好保护,这个被破了,就彻底被破了,其他破解,都是无法动到根基。
切记,千万不要在任何场合直接使用根密钥,降低泄漏的风险!!!!
离线
读取dram中数据可没那么容易,需要上大杀器
离线
或者软件本身存在缓冲区溢出漏洞被攻击了,然后ram被dump了,即使ram被搞了,你也只能做到非完美破解,你无法固化rom,一没key,二没签名,复制无从谈起
离线
对启动速度有影响,解密,验签,校验完整性,都是有代价的
离线