VoIP加密方案,BEEO加密算法原理及实现
二、 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,而接口函数中各个参数的定义完全相同于实际操作系统中相应函数的参数定义。这两个函数就是基本的程序接口。
三、 程序接口
这里,我们仅仅给出基于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的位顺序写入到输出数据中并紧密排列,然后把原始数据中剩余数据位紧密排列到输出数据中。如下图所示:
六、 加密强度估算
稍微计算一下就可以发现,用直接尝试三个加密矩阵的方法是不可取的,平均每个字节需要尝试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、 不需要数据库支持。如果取消公共密钥(因为私有密钥的加密强度已经足够),加解密过程甚至可以自由运行:不需要初始化,自动启动,自动停止。
八、 实际参数选择参考
这里,我们提出一组实际实现的参考,并强烈建议使用本加密方案的用户采纳这样一组参数,以保证实现结果互通性:
#define BEEO_DH_BYTES 20 /160bits/8
#define BEEO_MATRIX_BYTES 16 /128bits/8
#define BEEO_DH_FLAG 0x55cc12AB /报文标志
#define BEEO_VERSION 0x01010000 /报文版本号
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
{
uIn32 dwVersion; /版本号,现在使用0x01010000
uIn32 nPeerSeq; /已经收到的对方的报文序号,用于判断是否成功交换
uIn32 nLocalSeq; /发送的交换报文序号,决定是否为新的请求,要求!=0
uIn32 dwFlag; /报文标志,=BEEO_DH_FLAG
uChar dh[4][BEEO_DH_BYTES]; /DH特征值,前三个分别对应于Col、Row、Xor的DH特征值
uIn32 dwOffset[4];/前三个分别对应于Col、Row、Xor的位偏移量的DH特征值,取低16bits
uChar reserve[128]; /保留位,暂时全部=0
uChar cSum1,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电话的应用,我们可以提供本方案涉及的源程序、测试环境和各种协议栈的终端设备,我们真诚欢迎广大读者和加解密与我们展开讨论。
免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。