现在的很多产品都实现了OTA功能,通过OTA功能,产品可以实现功能不断地优化,给用更多的功能体验,当然最重要的,我猜大部分还是解决bug问题。
如果产品做成了畅销品,为了避免被山寨,还需要考虑自己的OTA不被破解,当年做的平衡车就在市场上出现了很多复制品,连bug都一样,而且还能兼容官方APP进行下载,真的让人气愤啊。幸运的是,当时有后台加持,检测到了山寨品的ID范围,直接发了一张“二向箔”全给升级成转头了。
开始做产品的时候,对于加密考虑的很少,OTA这事功能实现挺简单,要考虑防护,考虑的方方面面就很多了,首先bin文件的存储不能简单的放到线上,包括传输过程中也不能出现明文,最好每次更新被抓包的话,每次被抓包的加密数据都不一样,这样才足够可靠。
AES是一种对称加密机制,所谓对称,就是加密秘钥和解密秘钥是同一个,通信的双方约定好这个秘钥,发送的时候使用秘钥打包,接收时再用同样的秘钥进行解密。这种加密方式的缺点是秘钥的保存,一点被别人知道了秘钥就麻烦了。
对于嵌入式产品来说,通常的做法是约定好产品的秘钥,直接机密存储在产品的Flash中,服务器端也会存储一份,这样服务器在发送bin文件时,先使用秘钥进行加密,然后通过各种各样的通信方式传递给产品的主控,主控再使用秘钥进行解密还原bin文件。
这个过程中,通信的监听不会泄露秘钥,主要防护点就变成了产品端秘钥的保存上,实际上,可以通过非对称加密手段,在OTA之前,先将本次升级的秘钥传输给产品主控,然后在传输秘钥加密后的密文,这样来保证每次串数的密文不同。
这里先学习AES加密的原理和用法。
一. AES的基本结构
AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。
在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8bits)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同,如下表所示:
如果我们实现AES-128加密,这里推荐的加密轮数是10 。
AES的加密公式为C = E(K,P),在加密函数E中,会执行一个轮函数,并且执行10次这个轮函数,这个轮函数的前9次执行的操作是一样的,只有第10次有所不同。也就是说,一个明文分组会被加密10轮。AES的核心就是实现一轮中的所有操作。
AES的处理单位是字节,128bit,也就是16字节,这就是分组长度,我们把明文按照这个长度分成多个组。
每个分组P和输入密钥K都被是16个字节,分别记为P = P0 P1 … P15 和 K = K0 K1 … K15。
一般地,明文分组用字节为单位的正方形矩阵描述,称为状态矩阵。在算法的每一轮中,状态矩阵的内容不断发生变化,最后的结果作为密文输出。该矩阵中字节的排列顺序为从上到下、从左至右依次排列。
假设明文分组为P = abcdefghijklmnop ,其中的字符a对应P0,p对应P15。如下图所示:
上图表明,明文矩阵在一次一次的轮函数运算后被转化为了密文矩阵,按照上面的明文假设,加密过程中的数据变化非常大,如下图:
上面部分可以简单理解,我们首先把明文分组,每次加密之操作16字节,每次加密分10轮,在这10轮加密过程中,明文被轮函数转换了10次。
二. 秘钥的一生
秘钥是怎么作用的呢?秘钥其实也被分成10次,每一次执行轮函数,都让秘钥对相应轮数上的状态矩阵作用一下,也就是明文变化10次,就用10个不同的秘钥去作用10次,当然10个不同的秘钥肯定都是基于原始秘钥而来的。
16字节的密钥也是用字节为单位的矩阵表示,矩阵的每一列被称为1个32位比特字。
通过密钥编排函数 ,该密钥矩阵被扩展成一个44个字组成的序列W[0],W[1], … ,W[43]。
该序列的前4个元素W[0],W[1],W[2],W[3]是原始密钥,用于加密运算中的初始密钥;后面40个字分为10组,每组4个字(128比特)分别用于10轮加密运算中的轮密钥加,如下图所示:
上图中,如果Key = “abcdefghijklmnop”,则K0 = a, K15 = p, W[0] = K0 K1 K2 K3 = “abcd”
后面的10次秘钥矩阵是通过秘钥扩展函数进行扩展的,如下图
其中,T是一个有点复杂的函数,类似于前面明文的处理,各种代换和异或后计算出来的。目的就是打乱数据,让数据看不出规律。
三. 加密过程
W[0,3]是指W[0]、W[1]、W[2]和W[3]串联组成的128位密钥。加密的第1轮到第9轮的轮函数一样,包括4个操作:字节代换、行位移、列混合和轮密钥加。最后一轮迭代不执行列混合。
另外,在第一轮迭代之前,先将明文和原始密钥进行一次异或加密操作。下面是AES加解密的一个过程。
下面是对于加密过程的简要描述,大体了解加解密过程要做哪些事情。
字节代换,这就是一个查表,加密和解密过程需要一对数据表,分别叫做S盒和逆S盒。本质上就是一个二维数组,根据坐标查询对应的数据做代换,他们两个在轮加密过程中是可逆的。
行移位,这是一个简单的左循环移位操作。当密钥长度为128比特时,状态矩阵的第0行左移0字节,第1行左移1字节,第2行左移2字节,第3行左移3字节,如下图所示:
行移位的逆变换是将状态矩阵中的每一行执行相反的移位操作,例如AES-128中,状态矩阵的第0行右移0字节,第1行右移1字节,第2行右移2字节,第3行右移3字节。
列混合,这里也是涉及到了一对矩阵运算,两个列混合的矩阵的乘积正好是单位矩阵,一次你在加密和解密过程中,他们也是互为可逆的操作。
轮秘钥加,到这里才需要用到我们秘钥矩阵。
轮密钥加是将128位轮密钥Ki同状态矩阵中的数据进行逐位异或操作,如下图所示。其中,密钥Ki中每个字W[4i],W[4i+1],W[4i+2],W[4i+3]为32位比特字,包含4个字节,他们的生成算法下面在下面介绍。轮密钥加过程可以看成是字逐位异或的结果,也可以看成字节级别或者位级别的操作。也就是说,可以看成S0 S1 S2 S3 组成的32位字与W[4i]的异或运算。
具体的算法,试验完成再发出来。