1. 准备加密条件
用户在新浪微博登陆的时候,密码其实被经过了三次sha1加密,所使用的到信息包括了用户的密码,服务端的时间发送过来的servertime和一个叫做nonce的字段,后面两个是在登陆的时候从服务端get过来的,例,下边是我在测试的时候截取的消息:
图示1
这个阶段发生在你点击登陆的时候,这样客户端就可以利用这个字段进行密码的加密。
2. 使用js文件的加密算法进行加密
其实在js文件中的加密算法就是sha1算法,该js文件名称为sso.js,如下图示2所示
图示2
通过搜索sha1,你可以找到,加密密码的字段,如图示3所示,从图中,我们可以看到它利用了password,servertime,和一个叫做nonce的字段进行加密,使用了三次sha1加密
图示3
3. 分析加密的源码
1)先分析一下js源码
由于文件函数比较多,我直接摘取了关键的源码,如下所示
var i = 0;var g = 8;this.hex_sha1 = function(j) {var retB = b(f(j), j.length * g);var retH = h(retB);return retH;};var b = function(A, r) {A[r >> 5] |= 128 << (24 - r % 32);A[((r + 64 >> 9) << 4) + 15] = r;var B = Array(80);var z = 1732584193;var y = -271733879;var v = -1732584194;var u = 271733878;var s = -1009589776;for (var o = 0; o < A.length; o += 16) {var q = z;var p = y;var n = v;var m = u;var k = s;for (var l = 0; l < 80; l++) {if (l < 16) {B[l] = A[o + l]} else {B[l] = d(B[l - 3] ^ B[l - 8] ^ B[l - 14] ^ B[l - 16], 1)}var C = e(e(d(z, 5), a(l, y, v, u)), e(e(s, B[l]), c(l)));s = u;u = v;v = d(y, 30);y = z;z = C}z = e(z, q);y = e(y, p);v = e(v, n);u = e(u, m);s = e(s, k)}return Array(z, y, v, u, s)};var a = function(k, j, m, l) {if (k < 20) {return (j & m) | ((~j) & l)}if (k < 40) {return j ^ m ^ l}if (k < 60) {return (j & m) | (j & l) | (m & l)}return j ^ m ^ l};var c = function(j) {return (j < 20) ? 1518500249 : (j < 40) ? 1859775393 : (j < 60) ? -1894007588 : -899497514};var e = function(j, m) {var l = (j & 65535) + (m & 65535);var k = (j >> 16) + (m >> 16) + (l >> 16);return (k << 16) | (l & 65535)};var d = function(j, k) {return (j << k) | (j >>> (32 - k))};var f = function(m) {var l = Array();var j = (1 << g) - 1;for (var k = 0; k < m.length * g; k += g) {l[k >> 5] |= (m.charCodeAt(k / g) & j) << (24 - k % 32)}return l};var h = function(l) {var k = i ? "0123456789ABCDEF": "0123456789abcdef";var m = "";for (var j = 0; j < l.length * 4; j++) {m += k.charAt((l[j >> 2] >> ((3 - j % 4) * 8 + 4)) & 15) + k.charAt((l[j >> 2] >> ((3 - j % 4) * 8)) & 15)}return m}//sinaSSOController.preloginCallBack({"retcode":0,"servertime":1312582940,"nonce":"BUW9I5"})var password = "password";//servertime 是服务器传过来的值var servertime = "1312582940";//nonce 这个也是从服务器那边传过来的值var nonce = "BUW9I5";//var result = hex_sha1("" + hex_sha1(hex_sha1(password)) + servertime + nonce); var first = hex_sha1(password);var second = hex_sha1(first);var third = hex_sha1(second + servertime + nonce);alert(third)//结果输出:960ec4d4b7ffe64e382c1af4fa915758a2f0d372
其实,这整一个就是sha1的算法实现,在最后有一个测试的例子,下面,我使用java来编写这个算法实现,效果是一样的
2)使用java实现新浪微博密码加密算法
整个java就三个函数,实现也并不是很麻烦,其中,generateDigest函数主要是为了实现将内容用sha1算法进行加密
public class Encoder {public static void main(String[] args) {Long servertime = new Long(1312582940);String nonce = "BUW9I5";String password = "password";Encoder encoder = new Encoder();String firstDigest = encoder.generateDigest(password, "sha1");//System.out.println(firstDigest);String secondDigest = encoder.generateDigest(firstDigest, "sha1");//System.out.println(secondDigest);String encodedPassword = encoder.generateDigest(secondDigest + servertime + nonce, "sha1");System.out.println(encodedPassword);}private final char[] digits = { '0', '1', '2', '3', '4', '5', '6','7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };public String generateDigest(String content, String algorithm) {MessageDigest digest = null;try {digest = java.security.MessageDigest.getInstance(algorithm);} catch (NoSuchAlgorithmException e) {e.printStackTrace(System.out);}digest.update(content.getBytes());byte[] hash = digest.digest();StringBuffer sb = new StringBuffer();for (int i = 0; i < hash.length; i++) {sb.append(getByteAsHexString(hash[i]));}return sb.toString();}private String getByteAsHexString(byte b) {char[] buf = new char[2];int radix = 1 << 4;int mask = radix - 1;buf[1] = digits[(int) (b & mask)];b >>>= 4;buf[0] = digits[(int) (b & mask)];return new String(buf);}}
运行结果和用js实现的效果一模一样。
4. 结论
呃,在做东西的时候,有时候也要停下来想想这个东西到底是怎么实现的,为什么会这样,我开始的时候就因为在firebug看到密码是一串字母和数字,就想看个究竟,后来就发现它使用了三次sha1加密了用户密码,这样又能多学一点东西啦~
原文:/wm_at163/blog/static/13217349010744659292/