应网友之邀为大家提供一下WebQQ的MD5加密算法,因为MD5是WebQQ模拟登录过程中最难的部分,所以在这里不能不提及。本文只能提供C#的实现方法,其他语言版本可以参照C#作适当的修改便可。要操作MD5,C#中自带一个MD5类可供选择,相当方便。如果要自己写算法实现MD5也未曾不可,只是放着现成的类不用太浪费了。
首先引用空间:
using System.Security.Cryptography;
先说说WebQQ MD5加密的方式,公式是这样的:
md5(md5(hexchar2bin(md5(p)) + uin) + verify.toUpperCase());
verify是验证码,uin就是那段\x0的代码,p是密码
至于为什么是这样,作为菜鸟,我也说不清,懵里懵懂的给大家展示一下~!~只是用firebug分析到的Js里面的算法大致就是这个意思。其中这里最关键的函数,就是hexchar2bin了.我们先来罗列一下基础的MD5函数吧,其实是MD5的标准算法,直接贴在下面了,将普通文本转换成MD5。
View Code
/// <summary> /// 一次md5加密 ///http://www.cnblogs.com/uu102 /// </summary> /// <param name="md5_str">需要加密的文本</param> /// <returns></returns> public static string MD5_Encrypt(string md5_str) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5CryptoServiceProvider.Create(); byte[] bytes = System.Text.Encoding.ASCII.GetBytes(md5_str); byte[] bytes1 = md5.ComputeHash(bytes); System.Text.StringBuilder stringBuilder = new StringBuilder(); foreach (var item in bytes1) { stringBuilder.Append(item.ToString("x").PadLeft(2, '0')); } return stringBuilder.ToString().ToUpper(); }
再重载一次这个方法,以便能将字节数组也能转换成我们需要的MD5字符串
View Code
/// <summary> /// 将字节流加密 /// </summary> /// <param name="md5_bytes">需要加密的字节流</param> /// <returns></returns> private static string MD5_Encrypt(byte[] md5_bytes) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5CryptoServiceProvider.Create(); byte[] bytes1 = md5.ComputeHash(md5_bytes); System.Text.StringBuilder stringBuilder = new StringBuilder(); foreach (var item in bytes1) { stringBuilder.Append(item.ToString("x").PadLeft(2, '0')); } return stringBuilder.ToString().ToUpper(); }
接着,再上一个将字符串转换为MD5加密数组的函数
View Code
/// <summary> /// 获取文本的md5字节流 /// </summary> /// <param name="md5_str">需要加密成Md5d的文本</param> /// <returns></returns> private static byte[] MD5_GetBytes(string md5_str) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5CryptoServiceProvider.Create(); byte[] bytes = System.Text.Encoding.ASCII.GetBytes(md5_str); return md5.ComputeHash(bytes); }
接下来
View Code
/// <summary> /// 加密成md5字节流之后转换成文本 /// </summary> /// <param name="md5_str"></param> /// <returns></returns> private static string Encrypt_1(string md5_str) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5CryptoServiceProvider.Create(); byte[] bytes = System.Text.Encoding.ASCII.GetBytes(md5_str); bytes = md5.ComputeHash(bytes); System.Text.StringBuilder stringBuilder = new StringBuilder(); foreach (var item in bytes) { stringBuilder.Append(@"\x"); stringBuilder.Append(item.ToString("x2")); } return stringBuilder.ToString(); }
操作字节流
View Code
public class ByteBuffer { private byte[] _buffer; /// <summary> /// 获取同后备存储区连接的基础流 /// </summary> public Stream BaseStream; /// <summary> /// 构造函数 /// </summary> public ByteBuffer() { this.BaseStream = new MemoryStream(); this._buffer = new byte[0x10]; } /// <summary> /// 设置当前流中的位置 /// </summary> /// <param name="offset">相对于origin参数字节偏移量</param> /// <param name="origin">System.IO.SeekOrigin类型值,指示用于获取新位置的参考点</param> /// <returns></returns> public virtual long Seek(int offset, SeekOrigin origin) { return this.BaseStream.Seek((long)offset, origin); } /// <summary> /// 检测是否还有可用字节 /// </summary> /// <returns></returns> public bool Peek() { return BaseStream.Position >= BaseStream.Length ? false : true; } /// <summary> /// 将整个流内容写入字节数组,而与 Position 属性无关。 /// </summary> /// <returns></returns> public byte[] ToByteArray() { long org = BaseStream.Position; BaseStream.Position = 0; byte[] ret = new byte[BaseStream.Length]; BaseStream.Read(ret, 0, ret.Length); BaseStream.Position = org; return ret; } #region "写流方法" /// <summary> /// 压入一个布尔值,并将流中当前位置提升1 /// </summary> /// <param name="value"></param> public void Put(bool value) { this._buffer[0] = value ? (byte)1 : (byte)0; this.BaseStream.Write(_buffer, 0, 1); } /// <summary> /// 压入一个Byte,并将流中当前位置提升1 /// </summary> /// <param name="value"></param> public void Put(Byte value) { this.BaseStream.WriteByte(value); } /// <summary> /// 压入Byte数组,并将流中当前位置提升数组长度 /// </summary> /// <param name="value">字节数组</param> public void Put(Byte[] value) { if (value == null) { throw new ArgumentNullException("value"); } this.BaseStream.Write(value, 0, value.Length); } /// <summary> /// Puts the int. /// </summary> /// <param name="value">The value.</param> public void PutInt(int value) { PutInt((uint)value); } /// <summary> /// 压入一个int,并将流中当前位置提升4 /// </summary> /// <param name="value"></param> public void PutInt(uint value) { this._buffer[0] = (byte)(value >> 0x18); this._buffer[1] = (byte)(value >> 0x10); this._buffer[2] = (byte)(value >> 8); this._buffer[3] = (byte)value; this.BaseStream.Write(this._buffer, 0, 4); } /// <summary> /// Puts the int. /// </summary> /// <param name="index">The index.</param> /// <param name="value">The value.</param> public void PutInt(int index, uint value) { int pos = (int)this.BaseStream.Position; Seek(index, SeekOrigin.Begin); PutInt(value); Seek(pos, SeekOrigin.Begin); } #endregion #region "读流方法" /// <summary> /// 读取Byte值,并将流中当前位置提升1 /// </summary> /// <returns></returns> public byte Get() { return (byte)BaseStream.ReadByte(); } #endregion }
最后一个函数
View Code
public static string MD5_QQ_2_Encrypt(long uin, string password, string verifyCode) { ByteBuffer buffer= new ByteBuffer(); buffer.Put(MD5_GetBytes(password)); //buffer.Put(Encoding.UTF8.GetBytes(password)); buffer.PutInt(0); buffer.PutInt((uint)uin); byte[] bytes = buffer.ToByteArray(); string md5_1 = MD5_Encrypt(bytes);//将混合后的字节流进行一次md5加密 string result= MD5_Encrypt(md5_1 + verifyCode.ToUpper());//再用加密后的结果与大写的验证码一起加密一次 return result; }
大家凑合着看吧。对于这些代码实在是没什么话说,只好让各位自行研究了。代码绝对可用。本人博客每天都有原创更新,欢迎大家继续关注!