一、SASL概念
1、SASL跟OF什么关系?
Openfire(简称of),他是基于XMPP协议开发的,XMPP架构如下:
2、SASL到底是什么?
引用百度百科的废话:http://baike.baidu.com/view/1014674.htm
SASL全称Simple Authentication and Security Layer,是一种用来扩充C/S模式验证能力的机制。在Postfix可以利用SASL来判断用户是否有权使用转发服务,或是辨认谁在使用你的服务器。
SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要
说白了,就是一种身份验证机制,鉴权用户的身份用。一般很多网站验证身份也就是提交用户名和密码,服务端进行判断即可。SASL他也一样,只不过他的传输的内容多样化了。
3、SASL流程是如何的?
SASL验证方式多样化,有如下方式:CRAM-MD5, EXTERNAL, GSSAPI, ANONYMOUS, PLAIN, SECURID, DIGEST-MD5, LOGIN, NTLM。
of他支持哪些方式了?来看看of发送的东西:
看看上面黄色底部的,他支持了SASL四种验证机制。
我使用DIGEST-MD5看流程:
Of服务端:“喂,您好我有上面四种验证方式,你来选择一种告诉我吧”。
Of客户端:“老大,我要选择DIGEST-MD5”
Of服务端:“很好,来,我发送一个质询给你——其实就是用来加密的一些参数数据和加密算法,内容是:
realm="gsd",nonce="r52TbJKIRFuhMEahubcX9q1l35CtNWP22mf3eYCr",qop="auth",charset=utf-8,algorithm=md5-sess
注意了:基于xml的sasl对话,需要把内容信息经过base64编码,服务端发送了一个唯一的临时信息“nonce”,只能使用在一次验证中。
Of客户端:“好的,我将根据你发送过来的信息,对我的用户名和密码进行加密,得到一个值放在response(key)给你哈。等等”
发送的内容是:
charset=utf-8,username="*****",realm="gsd",nonce="r52TbJKIRFuhMEahubcX9q1l35CtNWP22mf3eYCr",nc=00000001,cnonce="9RvMVSw2INjosXIoTV09ycC8UPRDpWnPhXbSn/XW",digest-uri="xmpp/gsd",maxbuf=65536,response=1de05c0734e4aaf391a220eaca5e7b35,qop=auth,authzid="*****"
其中,这个非常重要:response=1de05c0734e4aaf391a220eaca5e7b35,他是根据什么来计算出来的了?
DIGEST-MD5算法,使用的参数数据有:cnonce,qop,nc,digest-uri,ha1,而
其中ha1这个值就是通过md5-sess这个算法来计算出来的,所需要的参数是: realm值,nonce,用户名,用户名密码,cononce。(md5-sess和md5应用上最大的区别,一个需要密钥,另一个不需要密钥)
Of服务端:“客户端兄弟,我收到你的数据了,我将从数据库中获取出该用户的密码,然后也根据我约定的algorithm=md5-sess算法进行加密(参数跟客户端加入的一模一样)得出response值,看看是否等于你发送过来的
response=1de05c0734e4aaf391a220eaca5e7b35,如果是相同,那么该用户就可以登录了,我将反馈一个信息给你:
4、SASL优势——digest-md5
密码不用在网络上传输,而且验证过程所交换的密钥只能使用一次。
二、android版本接口包的bug
问题描述:我们在开发过程使用上面的digest-md5 SASL验证方式验证用户登录,但是老是登录不成功。
问题在于:因为我们使用邮箱包含@,而xmpp中@的有特殊含义,所以在传输过程邮箱的@需要被转义成\40。但是asmack没有对”\”认真处理直接把邮箱的值放入到response中,而这个邮箱值是带引号的,会自动对\进行转义。
来看看asmck的粗心的地方:
digestResponse.append("username=\"");
digestResponse.append(m_authorizationId);
如果m_authorizationId=”haiji\\40163.com.cn”,他放入到“”中,会变成haiji\40163.com.cn少了一个\,到服务端他得到的是”haiji\40163.com.cn”,但他到服务端又是在引号里面,又需要对\转义变成了haiji163.com.cn,出错了。
正确的做法,应该看http://www.docjar.com/html/api/com/sun/security/sasl/digest/DigestMD5Client.java.html这里面的代码:
digestResponse.append("username=\"");
digestResponse.append(quotedStringValue(m_authorizationId));
三、快速对称加密算法——blowfish
1、对称加密算法
说白了密钥是相同的,非对称密钥是不相同的(RSA),逆向加密算法(md5)加密后不能还原的
2、什么是Blowfish算法
跟着百度来解读吧:
百度上面说blowfish算法是用来加密64bit分组(怎么分组?采用cbc模式——具体内容看我之前的文章《加密算法研究.docx》)长度的字符串,如果某一个字符串长度不够了?或者长度超过超过了怎么办?请看我的文章关于补位方面的知识《加密算法研究.docx》。
Blowfish算法有两个盒子unsignedlongpbox和unsignedlongsbox,这两个盒子是根据源密钥pbox和sbox跟我们用户提交的密钥变换得到的。Pbox和sbox是固定的,sbox他是根据“π”来生成的。具体流程:
P数组由18个32位子密钥组成:
P1,P2,P3,……P18
4个32位的S盒,每个有256个单元:
S[1,0],S[1,1],S[1,2],……S[1,255]
S[2,0],S[2,1],S[2,2],……S[2,255]
S[3,0],S[3,1],S[3,2],……S[3,255]
S[4,0],S[4,1],S[4,2],……S[4,255]
计算过程如下:
1.初始化P数组,然后是4个S盒用固定的串.这些串由π的十六进制组成.
2.用密钥的第一个32位与P1异或,用密钥的第二个32位与P2异或,依此类推,直到密钥的所有位(直到P18).周期性地循环密钥的所有位直到整个P数组与密钥异或完为止.
3.利用Blowfish算法加密全零串,其密钥为在第1和第2步中描述的子密钥.
4.用第3步的输出取代P1和P2.
5.利用Blowfish算法加密第3步的输出,其密钥为修改过的子密钥.
6.用第5步的输出取代P3和P4.
7.重重上述操作,直到P数组的所有元素及4个S盒全部被连续变化的Blowfish的输出所取代.
Blowfish是一个由16轮构成的Feistel结构.输入是64位数据x,加密过程为:
把x分成32位的两部分:xL,xR
对于i=1至16
xL=xL^Pi
xR=F(xL)^xR
交换xL和xR(最后一轮取消该运算)
xR=xR^P17
xL=xL^P18
重新合并xL和xR
四、Blowfish家住of
Of的blowfish密钥放在哪里?请查看数据库ofProperty
五、遗留问题以及改进
1、【问题】Of为什么采用blowfish保存密码?这个待考证……
密码应该尽量使用单向散列算法的
2、【解决】
目前我们要求是对密码先使用base64(HMAC-SH1(password))得到单向的散列字符串,然后在使用blowfish进行加密,最后保存到数据库中。