VoIP加密方案,BEEO加密算法原理及实现
本方案力争以简单的运算,规定一种适应于加密在 Internet上传输的IP电话(包括信令、媒体以及短信等)相关业务的较高强度的加密方法——BEEO。本方案适应的信令标准包括SIP、MGCP、 H.323,适应的媒体传输方式为RTP,适应的网络结构包括客户服务器模式和端到端模式。
一、基本原理
本方案规定的加解密所处的网络位置在OSI网络体系结构的第五层,加密的内容是TCP/UDP的负载,VoIP信令结构也属于被加密的内容。
在发送端,把输入内容按数据位排列成矩阵,按照协商的方式和密钥形成一个列加密矩阵、行加密矩阵和加扰矩阵,用列加密矩阵对输入数据的列进行数据位交换,用行加密矩阵对输入数据的行进行数据位交换,用加扰矩阵对数据块按字节进行异或操作,从而达到加密的目的。在接收端,使用同样三个矩阵的逆矩阵顺序进行去扰、行恢复和列恢复,还原出原始数据。
在整个加解密过程中,我们仅仅使用数据位交换和异或操作,于是我们把这种加密方法命名位BEEO,英文字母取自单词Bit-Exchange和Exclusive-OR。
为了计算简单而且保证输入输出的数据长度完全一样,我们建议使用8行×N列矩阵,这样,每个字节对应于矩阵的一列,顺序排列形成矩阵。
我们使用密钥交换算法产生一个属于通讯双方共有的6个私有数值,三个作为密钥,与公共密钥一起计算一个三个HASH数字签名;剩余三个作为矩阵生成偏移量;把数字签名根据矩阵生成偏移量进行循环移位,生成列交换矩阵、行交换矩阵和加扰矩阵。
加密矩阵生成方式很多,一般情况下,我们建议选用8行×32列共计128位的加密矩阵;采用DH(Diffie-Hellman)算法完成密钥交换,并选择密钥和矩阵生成偏移量的DH特征值长度分别为160位和16位;选择MD5产生HASH数字签名,数字签名长度为128位;
二、DH交换
DH交换的目的在于以明文的方式交换密钥特征,形成只有参与通讯的双方才知道而且通讯双方一定知道的私有数值。
确定一个模数(如p)以及底数(如g);两个通讯设备(如MA、MB)各随即选取一个加密指数(如a和b),以明文方式报告自己的DH特征值(如A和B),然后各自进行乘幂计算以产生这个私有数值:

通讯双方选择的加密指数是不公开的,应该相对较大,而且应该通过某种随即算法保证这个加密指数是变化的。其次,通讯双方每隔一定时间,应该申请更改私有密钥,以避免黑客获得太多的数据样本并破译通讯内容。
针对基本原理中提到的各个特征数据的长度,我们规定,用于生成密钥的加密指数至少应该达到12位,用于生成偏移量的加密指数建议选择8位,这样,六个加密指数的选择空间总和至少达到60位。
一般情况下,在客户端登录以前,客户端向服务器端发起DH交换请求报文,报告自己的6个DH特征值,服务器端收到请求以后,向用户发送自己的6个DH特征值,双方分别使用对方的DH特征值和自身的加密指数计算出私有密钥并生成最终的加密矩阵。虽然这一组报文是以明文方式传输的,但即便黑客得到了这些明文,也知道整套算法的所有细节,黑客也不足以形成这个私有密钥,这是使用DH交换的基本出发点。
对于媒体传输,通讯双方并不存在客户端和服务器的区分,这时我们要求,在通过信令完成RTP参数交换以后,双方各自在第一时刻发起DH交换请求,而且任何一方收到DH交换请求以后,立即向用户发送自己的DH特征值,从而建立起这个加密信道。
这里需要重点阐述一下加密指数。我们要求设备产生的加密指数是随机的、变化的,而且6个加密指数之间没有任何的联系。事实上,某些嵌入式设备根本不能产生随机数,当程序运行到某一条指令的时候,时钟是一个固定值,随机算法的种子是一个固定值,甚至各个寄存器也是一个固定值,用随机算法产生的下一个数据也是固定值。而对于PC环境,虽然时钟是变化的,有可能获得一个真正随机的种子,但使用rand()等函数获得的伪随机序列其实是一个固定序列。在程序启动的时候以及运行过程中,最好读一小段语音数据或者网路数据,以这些数据进行运算和组合,形成加密指数。
三、程序接口
这里,我们仅仅给出基于UDP实现的相关协议(包括MGCP的全部信令、SIP的全部信令、H.323的部分信令、RTP媒体、RTCP媒体控制)的接口,而基于TCP实现的相关协议(H.323的部分协议)的接口将在其他文档中给出。
对于UDP传输,一般情况下,我们在每个设备上建立一个加密参数索引表,根据UDP发送端口、UDP接收端口和UDP接收地址(IP地址)进行索引。每次发送的时候,检查DH交换是否完成,如果没有完成,则主动放弃这个报文的发送,并发送DH交换请求报文;如果已经完成,则加密以后发送出去;每次接收的时候,检查DH交换是否完成,如果没有完成,检查这个报文是否为DH交换报文,尝试完成DH交换,并计算位交换矩阵和异或矩阵;如果已经完成,则按照DH交换报文特征进行过滤以后报告给应用程序。当然,在这个过程中,任何一个设备可以随时启动对任何一个连接的再次DH交换,并且在某个连接空闲一段时间以后关闭这个连接。
(在交换报文中,我们还需要定义一个叫做报文序号的变量,并强制规定这个需要不能为0。每个设备自行管理属于自己的报文序号。在发送交换报文的时候,设备应该把自己的报文序号和已经收到的对方的报文序号发送给对方;另外一方根据接收到的报文序号判断协商是否完成,或者是否开始了一次新的交换过程)
(这样实现,必然会丢弃信道建立初期的一到两个信令单元,但我们可以相信这并不会影响VoIP的实现。因为在SIP或者MGCP或者H.323的UDP信令传输过程中,已经通过重传报文规避了丢包风险;而RTP传输中,信道建立初期丢失几个报文几乎不会影响通讯质量。如果确实不允许丢弃报文,我们可以开辟少量的缓存空间,把这些报文保存下来,一旦DH交换完成,再把这些报文发送出去。)
我们重载操作系统中原来的UDP收发函数(一般命名为sendto、recvfrom或其他类似字样),把发送函数定义成BEEO_sendto,把接收函数定义成 BEEO_recvfrom,而接口函数中各个参数的定义完全相同于实际操作系统中相应函数的参数定义。这两个函数就是最基本的程序接口。
通讯双方选择的加密指数是不公开的,应该相对较大,而且应该通过某种随即算法保证这个加密指数是变化的。其次,通讯双方每隔一定时间,应该申请更改私有密钥,以避免黑客获得太多的数据样本并破译通讯内容。
针对基本原理中提到的各个特征数据的长度,我们规定,用于生成密钥的加密指数至少应该达到12位,用于生成偏移量的加密指数建议选择8位,这样,六个加密指数的选择空间总和至少达到60位。
一般情况下,在客户端登录以前,客户端向服务器端发起DH交换请求报文,报告自己的6个DH特征值,服务器端收到请求以后,向用户发送自己的6个DH特征值,双方分别使用对方的DH特征值和自身的加密指数计算出私有密钥并生成最终的加密矩阵。虽然这一组报文是以明文方式传输的,但即便黑客得到了这些明文,也知道整套算法的所有细节,黑客也不足以形成这个私有密钥,这是使用DH交换的基本出发点。
对于媒体传输,通讯双方并不存在客户端和服务器的区分,这时我们要求,在通过信令完成RTP参数交换以后,双方各自在第一时刻发起DH交换请求,而且任何一方收到DH交换请求以后,立即向用户发送自己的DH特征值,从而建立起这个加密信道。
这里需要重点阐述一下加密指数。我们要求设备产生的加密指数是随机的、变化的,而且6个加密指数之间没有任何的联系。事实上,某些嵌入式设备根本不能产生随机数,当程序运行到某一条指令的时候,时钟是一个固定值,随机算法的种子是一个固定值,甚至各个寄存器也是一个固定值,用随机算法产生的下一个数据也是固定值。而对于PC环境,虽然时钟是变化的,有可能获得一个真正随机的种子,但使用rand()等函数获得的伪随机序列其实是一个固定序列。在程序启动的时候以及运行过程中,最好读一小段语音数据或者网路数据,以这些数据进行运算和组合,形成加密指数。
三、程序接口
这里,我们仅仅给出基于UDP实现的相关协议(包括MGCP的全部信令、SIP的全部信令、H.323的部分信令、RTP媒体、RTCP媒体控制)的接口,而基于TCP实现的相关协议(H.323的部分协议)的接口将在其他文档中给出。
对于UDP传输,一般情况下,我们在每个设备上建立一个加密参数索引表,根据UDP发送端口、UDP接收端口和UDP接收地址(IP地址)进行索引。每次发送的时候,检查DH交换是否完成,如果没有完成,则主动放弃这个报文的发送,并发送DH交换请求报文;如果已经完成,则加密以后发送出去;每次接收的时候,检查DH交换是否完成,如果没有完成,检查这个报文是否为DH交换报文,尝试完成DH交换,并计算位交换矩阵和异或矩阵;如果已经完成,则按照DH交换报文特征进行过滤以后报告给应用程序。当然,在这个过程中,任何一个设备可以随时启动对任何一个连接的再次DH交换,并且在某个连接空闲一段时间以后关闭这个连接。
(在交换报文中,我们还需要定义一个叫做报文序号的变量,并强制规定这个需要不能为0。每个设备自行管理属于自己的报文序号。在发送交换报文的时候,设备应该把自己的报文序号和已经收到的对方的报文序号发送给对方;另外一方根据接收到的报文序号判断协商是否完成,或者是否开始了一次新的交换过程)
(这样实现,必然会丢弃信道建立初期的一到两个信令单元,但我们可以相信这并不会影响VoIP的实现。因为在SIP或者MGCP或者H.323的UDP信令传输过程中,已经通过重传报文规避了丢包风险;而RTP传输中,信道建立初期丢失几个报文几乎不会影响通讯质量。如果确实不允许丢弃报文,我们可以开辟少量的缓存空间,把这些报文保存下来,一旦DH交换完成,再把这些报文发送出去。)
我们重载操作系统中原来的UDP收发函数(一般命名为sendto、recvfrom或其他类似字样),把发送函数定义成BEEO_sendto,把接收函数定义成 BEEO_recvfrom,而接口函数中各个参数的定义完全相同于实际操作系统中相应函数的参数定义。这两个函数就是最基本的程序接口。
另外,我们规定了一些辅助的程序接口,其中比较重要的接口有beeo_force_setup()和 beeo_established()。在发送实际数据之前,调用beeo_force_setup()将可以提前建立加密通道,保证不丢弃任何实际通讯信令单元。beeo_established()用于判断加密信道是否已经建立。
四、加密运算方法和运算量估算
加密运算方法很多,在这里我们规定一种简单的算法。
对于列加密,加密矩阵的每一列有8位数据,也就是说具有256种数值,我们对应规定256种加密形态。为了运算简单,我们规定:按列对齐矩阵,顺序计算各列。从某一列的最高位开始,首先把输入数据对应列中为1的位顺序写入到输出数据中并紧密排列,然后把原始数据中剩余数据位紧密排列到输出数据中。如下图所示:

如果用软件变成实现这种列加密,可以采用两种实现方式,第一种方式是编制一个的二维(256×256)单字节索引表,用查表法完成;第二种是根据加密矩阵进行逐位转换。第一种方法速度块,只需要一次操作即可完成加密和解密,但加密和解密各需要64K内存;第二种方法不需要增加内存,但每转换一个字节需要进行 8次比较,速度较慢。我们建议在嵌入式系统上使用第二种方式,因为这种方法使用的内存很少,便于CPU的Cache调度管理;而在PC环境下可以使用第一种方式,因为在这样的环境下,内存成本是很低的。
对于行加密,把输入内容与行交换矩阵按列对齐,从第一列开始,把输入内容的第一列中对应行加密矩阵的第一列中为1的位和第二个列中对应行加密矩阵的第一列中为1的位进行交换;把输入内容的第二列(注意:这时的第二列已经跟第一列完成了位交换)中对应行加密矩阵的第二列中为1的位和第三列中对应行加密矩阵的第二列中为1的位进行位交换,直到最后一个字节为止。倒数第二列需要与最后一列进行位交换,而最后一列与第一列进行位交换。如下图所示:

显然,用软件很容易实现这钟行加密,每列只需要2次运算,不需要消耗内存。
对于加扰,由于采用异或运算,原理和实现方法都很简单,在此不再赘述。
运算过程种,如果矩阵不够长(比输入内容短),我们在使用一次以后再次从第一列开始重复使用。
从以上的讨论种可以算出,即使采用最慢的运算方法,每完成一个字节的加密或者解密,也最多只需要40个CPU处理周期。
五、加密矩阵的运算量估算
不难发现,在前面的DH交换设计中,我们把私有密钥和矩阵生成偏移量分成6个不同的DH特征值进行交换,而不是采用一个特征值进行交换,目的何在?
这是为了把计算加密矩阵的运算量降低到一个合适的水平。
我们在ARM7的CPU上进行过测试,我们把加密指数取值空间设计为212(最大4096),把私有密钥长度设定为768位,这种情况下,平均每计算一次私有密钥需要120M个CPU处理周期。同样在这种情况下,一旦黑客获取了公共密钥,他只需要尝试4096次就肯定可以完成解密。为了得到足够的加密强度,我们需要把加密指数取值空间提高到248以上,这时,一般的嵌入式CPU几乎就不能正常工作了。
现在,我们分别计算6个DH特征值,取值空间为212、长度为160位的密钥需要计算3个,取值空间为28、长度为8位的密钥需要计算3个,加密指数的取值空间达到了260,而总计算量只有70M (228)个CPU处理周期,这样,一般的CPU都可以在一秒钟以内完成运算。
当然,这个运算量还可以减小,但如果太小了,解密就容易了。
六、加密强度估算
稍微计算一下就可以发现,用直接尝试三个加密矩阵的方法是不可取的,平均每个字节需要尝试223次,解析出8个字节,就至少需要尝试2184次,相当于1056次尝试解码,运算量太大,至少远远大于下面将要讨论的穷举方法的运算量。
对于IP电话网络,设备存在两种工作模式:C/S模式和E2E模式。例如SIP在登录和发起呼叫的时候,工作在C/S模式,信令都通过Server进行转发;而在传输短信和媒体的时候,为了节约带宽资源并降低媒体中继设备的负荷,将努力使用端到端模式。这样就带来一个问题:在整个通讯网络上,所有设备的公共密钥必须是一样的,否则,在进行端到端通讯的时候,通讯双方还必须通过某种途径交换公共密钥。MGCP和H.323也有同样的特性, H.323协议栈甚至允许设备直接发起端到端呼叫。显然,这个全网统一的公共密钥也就成了全网统一的公开密钥,加密强度纯粹靠私有密钥来保障。
现在我们假定黑客已经知道了公共密钥、已经获取了私有密钥的交换报文、完全了解加解密实现方法,然后,黑客穷举所有可能的密钥,直到成功。这种情况是本算法最脆弱的情况。我们来估算一下这种黑客需要大致进行多少次运算才能完成解密。
前面的讨论中已经给出私有密钥的加密指数总长度为60位,组合模式有260种,从计算矩阵到完成一组报文的解密,每种组合需要228个CPU处理周期,穷举完毕需要288(或者1027)个CPU处理周期,相当于10G的CPU处理1017秒(3千万年),应该说加密强度还是比较高的。
七、BEEO的优点
从以上讨论中,我们不难发现BEEO具有一下优点:
1、不要求改变信令协议栈和媒体传输协议栈的任何实现代码,只是重载网络数据发送和接收函数,即可完成加解密。
2、加解密过程不会改变信令单元的长度,除了DH交换过程极少量地增加一些信令单元以外,不会给带来其他的网络负担。
3、对网络拓扑结构没有要求,既可以工作在客户服务器(C/S)结构下,又可以工作在端到端(E2E)结构下;既可以工作在服务器上,又可以工作在客户端,而且在所有环境下代码完全一样。
4、可以不更换/更改中继设备。原有网络中已经存在的中继设备,例如媒体中继设备,如果不进行中继内容判断,则可以完全按照原有方式进行运行,不需要加密,也不需要解密,因为加解密过程是端到端进行的。
5、不需要数据库支持。如果取消公共密钥(因为私有密钥的加密强度已经足够),加解密过程甚至可以自由运行:不需要初始化,自动启动,自动停止。
6、运算量极少。虽然计算位交换矩阵的过程相对比较复杂,但毕竟这个过程只会在相对较长的时间里发生一次,这种复杂是允许的。而实际传输的时候,加解密过程都极其简单,以120Kbps流量(相当于单路语音经过G.711编码后的最大流量)计算,编解码运算量总和可以控制在1MIPS以内,几乎可以忽略不及。
7、CPU的依赖性小。由于运算量小、内存消耗低(每通道不超过512字节)、指令简单(加解密使用的指令不外乎AND、OR、 XOR、NOT等最基本的指令),基本上可以工作在任意CPU上。当然,实现DH或者某种HASH算法的时候,往往需要对超长数据进行乘除法等操作,显然比较复杂,但即便在Intel PentiumM这样的CPU上,也没有简单的实现方法,只能依赖于基本指令实现。
8、允许嵌套使用,在增加少量运算量的情况下,进一步提高加密强度。
八、实际参数选择参考
这里,我们提出一组实际实现的参考,并强烈建议使用本加密方案的用户采纳这样一组参数,以保证实现结果互通性:
#define BEEO_DH_BYTES20/160bits/8
#define BEEO_MATRIX_BYTES16/128bits/8
#define BEEO_DH_FLAG0x55cc12AB/报文标志
#define BEEO_VERSION0x01010000/报文版本号
static unsigned char beeo_PatternForMatrix[BEEO_DH_BYTES] =
{/用于生成矩阵的模数
0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x5E,0x7E,
0xC6,0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF
};
static unsigned char beeo_BaseForMatrix[BEEO_DH_BYTES] =
{/用于生成矩阵的底数
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x57,0x41,0x54,0x45,0x52,0x54,0x45,0x4b,
};
/用于生成位偏移量的模数
static uIn16 beeo_baseForOffset =3;
/用于生成位偏移量的底数
static uIn16 beeo_patternForOffset = 0xc567;
/*定义密钥交换报文。
对于长整形数据,需要转换成网络字节顺序。*/
typedef struct tagBeeoDHPackage
{
uIn32dwVersion;/版本号,现在使用0x01010000
uIn32nPeerSeq;/已经收到的对方的报文序号,用于判断是否成功交换
uIn32nLocalSeq;/最新发送的交换报文序号,决定是否为新的请求,要求!=0
uIn32dwFlag;/报文标志,=BEEO_DH_FLAG
uChardh[4][BEEO_DH_BYTES];/DH特征值,前三个分别对应于Col、Row、Xor的DH特征值
uIn32dwOffset[4];/前三个分别对应于Col、Row、Xor的位偏移量的DH特征值,取低16bits
uChar reserve[128];/保留位,暂时全部=0
uCharcSum1,cSum2,cSum3,cSum4;/校验和
} BEEO_DH_PACKAGE;
结束语
近年来,IP电话的发展可谓风起云涌,而IP电话的通讯安全问题一直存在着隐患——帐号可能被窃取,媒体(语音和视频)可能被监听。如果采用3DES等算法进行加密,生产成本和带宽成本都将有所增加。在生产成本方面,现在的IP电话机或者IAD设备,加上家庭网关、留言电话等复杂功能以后,要求生产成本(包括外科、加工费在内)控制在二百多元人民币/线以内,我们很难要求生长厂商再提高CPU性能。带宽方面,我们使用G.723.1替代G.729,目的就在于进一步压缩带宽,而实现结果是增加了至少50MIPS的CPU开销,换来了不到10%的带宽,可见带宽资源的宝贵。
本方案虽然加密强度不是特别高(对于民用级通讯已经足够),但通过空间的数据位交换以及加扰过程,成功地保证了帐号和媒体的安全性,而附加的成本仅仅是1MIPS的CPU开销和不到1‰的带宽损耗。
为了共同促进IP电话的发展,尤其是推广加密IP电话的应用,我们可以提供本方案涉及的源程序、测试环境和各种协议栈的终端设备,我们真诚欢迎广大读者和加解密专家与我们展开讨论。
本文摘自《EDN电子设计技术》