存档

文章标签 ‘.net’

飞信2010身份验证算法成功破解

三月 1st, {2010 61 条评论 24,557 人阅读过  

周末简单抓包分析了一下飞信的登录协议,昨天晚上一直延续到现在都在研究它的身份验证的算法,身份验证的过程大体搞清楚了,跟旧版本的形式差不多,最大的变化是2010不再是将密码的散列值进行传输,而是使用RSA非对称加密之后再进行传输。

在SipC注册的过程中,客户端生成一个CNOUCE,然后发给服务器,服务器自己生成一对密钥,私钥自己保留,公钥放到key里面发给客户端,随同公钥一起发给客户端的还有服务器生成的key值,和一个数据签名signature。

客户端的加密过程如下:

客户端将三个字段的UTF8数组合并成一个byte[](在C里面也就是unsigned char*),然后对这个byte[]进行RSA加密,加密使用了PKCS#1 1.5的padding方式,查了一下.net只支持两种padding,相比于no padding来说更安全一些,而且它每次加密之后的结果都是不一样的,另外使用这种Padding进行加密时,要加密的数据至少要比密钥的模长短至少11个字节,否则就会加密失败。

下面说一下是将哪三个字段加密了,第一个字段是服务器发过来的nonce,第二个字段是密码,第三个字段是一个aeskey。

nonce这个没什么好说的,就是Sipc注册的时候返回来的nonce值,直接放在前面就可以了。

password是这个是困扰我时间最长的,飞信在计算response值的时候,把这三个字段当成16进制字符串,也就是类似于”ACFDF768597″这种,它将它们转换成UTF8数组,每两个字节转换成一个字节的UTF8数组,但原始密码肯定不可能是这种标准的16进制字符串,必然是做过某种处理,注意到在发送验证信令的后面附上了一个值algorithm=”SHA1-sess-v4″,然后我意识到密码可能是经过SHA1散列处理了,事实上确实如此,只不过不如我想象的那么简单。在linux下用openssl提供的加密算法来测试,返回的却一直都是Unaccpectable,一直以为是加密算法出了问题,反复修改测试各种加密算法,无数次失败后终于决定回到windows下改用.net测试,用飞信用到的.net framework里提供的加密算法进行加密,确保加密算法没有问题,庆幸自己多掌握了几门语言,虽然写得不如别人漂亮,但能看懂对我来说就足够了。

用.net写了一个sipc验证的程序,结果总是提示密码错误,也就是说密码的处理上确实存在问题,折腾了两三个小时终于弄明白飞信对密码都动了哪些手脚。它将字符串fetion.com.cn:password的utf8字符串进行SHA1做散列,然后得出一个16进制字符串,SHA1是20个字节的,16进制字符串有40个字节,然后再将这个字符串前面再附上一个user-id,再做散列,得到的字符串就是最后要加密的密码,user-id这个东西在旧版本里面我就注意到,但事实上它并没有起到什么作用,新版本里面居然把它用到身份验证里面来了,至于user-id的获取,这个连看也不用看,肯定在SSI登录的完成的时候会在返回的数据包中包含。

再就是aeskey这个字段,这真是个让我哭笑不得的字段,从名字上看上去好像是用到了AES对称加密,事实上在生成这个字段的时候也确实用到了.net关于AES算法的Rijndael类,冒然贴一段代码:

1
2
3
4
5
6
7
public static string GenerateKey()
{
     Rijndael rijndael = Rijndael.Create();
     rijndael.KeySize = 0x100;
     rijndael.GenerateKey();
     return BinaryToHex(rijndael.Key);
}

简单地说一下,第一句话创建一个Rijndael对象,第二句话指定密钥的长度为256个字节,GenerateKey()这个方法在MSDN里面解释是说生成一个随机密钥,仔细查看了.net关于Rijndael的代码,发现它在它的父类中声明,是个抽象方法,而Rijndael类并没有对这个方法进行重写,也就是说这里调用的这个方法是个空方法,我把这个方法注释掉以后再调用这个方法,仍然可以生成随机字符串。最有意思的地方是这里并于AES的只有这几句话,根本没有涉及到任何加密的代码,也就是说飞信开发人员需要一个64字节的随机字符串附在密码后面,一起加密,这样使要加密字符串更长一些,加密的强度也就更大一些,而飞信开发人员嫌麻烦,懒得再重新写一个生成这样一个随机字符串的方法,于是就借用AES里面的随机密钥,其实整个身份验证过程跟AES没有半点关系,即使我把这个aeskey换成了一个固定值如:“4A026855890197CFDF768597D07200B346F3D676411C6F87368B5C2276DCEDD2”也一样能够验证通过,而光是这个名字就给了我很大的误导。

总而言之,飞信2010身份验证算法已经搞定了,在windows下用.net测试也通过了,接下来如何移植到C+openssl就是以后的事了,并于openssl实现这些相关的算法有时间再写吧。

声明:本文纯粹用于学习,不出于任何商业利益或者有任何损坏飞信利益的行为,涉及内容比较抽象,靠此文不可能写出飞信登录程序,希望权威部门不要找我麻烦。

分类: Protocol 标签: , ,

飞信2010登录协议分析

二月 27th, {2010 17 条评论 17,816 人阅读过  

飞信2010出了有一段时间了,但到现在也只是beta版,所以就没怎么关注它,今天下载了一个分析了一下它的协议,才发现飞信迟迟不推出新版本是因为它的协议有了比较大的变动,似乎想要把我们这些山寨货赶尽杀绝,也就是传说中的V4版本的协议,很多信令后面都加上了V4标志,这也意味着想要适应2010,协议部分就必须重写。

飞信的登录协议比以前的版本有了显著的变化,最明显的变化在于它对登录信息的加密处理上,旧版本的飞信登录信息的加密让人看起来有点小儿科,把几个字段这样加起来做散列,然后再那样加起来做散列,来来回回折腾最后得出一个response传回服务器验证。

2010的登录信息处理采用了非对称加密RSA算法。先贴几个抓出来的协议包吧:
1.SSI登录
SSI登录仍然采用了https登录,登录服务器应该没变,还是uid.fetion.com.cn。登录参数变了,加上必须的参数uri如下:

https://uid.fetion.com.cn/ssiportal/SSIAppSignInV4.aspx?mobileno=1348888888&&domains=fetion.com.cn%3bm161.com.cn%3bwww.ikuwa.cn&&v4digest-type=2&v4digest=password

注意:这里的密码也不再是v3里面的明文密码了,呵呵。

其中demains里面有三个域名,第一个应该是必须的,后两个不知道是哪家第三方的公司的域名,估计可以去掉,v4digest-type是密码类型,有如下定义:

1
2
3
4
5
6
public enum PasswordTypeEnum
{
    V3,
    V4Temp,
    V4
}

v4digest就是密码了,然后还有一些可选参数像algorithm之类的我也就没细看它的功能。

2.sipC注册

R fetion.com.cn SIP-C/4.0
F: 916098834
I: 1
Q: 1 R
CN: 1CF1A05B2DD0281755997ADC70F82B16
CL: type=”pc” ,version=”3.6.1900″

这是sipC注册信息,CN就是旧版本里的cnouce , CL就是客户端信息了。服务器收到后回复信令:

SIP-C/4.0 401 Unauthoried
F: 916098834
I: 1
Q: 1 R
W: Digest algorithm=”SHA1-sess-

v4″,nonce=”389CE97D594B290366DCD4CC2DA5368D”,key=”D84CA40D849FEF3B45F02BBA6900D2A1B3010001″,signature=”62F5BA9D9146D477CDECAE1FD47098D0CABBFD31D683B5223B5D52″

为了节约篇幅key和signature的内容我都删去了一部分,key就是共享密钥,这个用来对验证信息做非对称加密用的,signature是签名,用来对密钥信息做验证的。

3.sipC验证

R fetion.com.cn SIP-C/4.0
F: 916098834
I: 1
Q: 2 R
A: Digest

response=”5041619340F10D101149E45A8E2343294E8D5F4F5086C24703EE00CAA4DF8F9D2951E9F285C458F556

7454F5C35084A8CB7C5E3AA8D31D1FC3B9DD7CF395631E5EDE73E2E683D54C9E521443D31792E18B81CA26542BF5

79F662459CD5F6E4C0EC29767B6C5F775C10AF19B544B6957AC98FF6A420C7486BE68837A576036118″,algorith

m=”SHA1-sess-v4″
AK: ak-value
L: 426

消息体里面的xml信息就不贴出来了。最关键的部分是通信sipC注册返回的信息来计算这个response,计算response共需要用到4个参数,publickey,nouce,password,aeskey.

publickey刚才注册返回的key值。

nouce 注册返回的nouce值。

password用户密码。

aeskey 用户通过 Rijndael算法生成的AES串。

response的计算规则是:

1.str = nouce + password + aeskey

2.对str进行RSA非对称加密,RSA算法具体细节我不懂,不过查看了一个微软MSDN了也大体知道是怎么工作的,它在计算的时候需要Exponent(e,公钥指数),Modulus(n , 模),D (d , 私钥指数),不过我看飞信在传递RSA参数的时候只是指定了e和n,e是截取了公钥的前256的字符,n是截取了公钥的256个以后的字符。

3.通过2计算出来的参数对str进行加密,得到的就是response值。

将验证信令发送到服务器之后服务器会返回用户的详细信息,这与之前的版本之比也是一大改进,省去了再额外构造信令去GetPersonalInfo

另外,新版本的协议在获取用户信息上改动也很大,sipC验证完成后用户个人信息和联系人列表就会随返回消息一同发过来,旧版本会先发送GetContactList信息获取用户列表,然后再构造一个庞大的Subscription去订阅这些用户的消息,新版本将这些完全简化了,发送如下一条信令就可以订阅所有用户的信息,用户信息就会被一条一条地推送过来。

SUB fetion.com.cn SIP-C/4.0
F: 916098834
I: 8
Q: 1 SUB
N: PresenceV4
L: 95

<args>
<subscription self="v4default;mail-count" buddy="v4default" version="320595567" />
</args>

格式如下:

BN 916098834 SIP-C/4.0
N: PresenceV4
I: 1
L: 190
Q: 5 BN

<events>
    <event type="PresenceChanged">
        <contacts>
            <c id="601820518"><pr di="" b="0" d="" dt="" dc="0"/></c>
            <c id="464997176"><pr di="" b="0" d="" dt="" dc="0"/></c>
        </contacts>
    </event>
</events>

将字段名称也简化了,这样有助于在数据传输时候节省字节数,效率会更高一些。

OK,重要的变化差不多也就这些了,真要动手去写的话也够我忙活一阵子的了,现在没那么多时间了,要老老实实专心做项目了,2010到现在也只是个beta版,我先静观其变吧,免得做无用功。

分类: Protocol 标签: , ,