[c#] WebQQ密碼MD5加密算法的C#實現


    應網友之邀為大家提供一下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;

        }

 大家湊合着看吧。對於這些代碼實在是沒什么話說,只好讓各位自行研究了。代碼絕對可用。本人博客每天都有原創更新,歡迎大家繼續關注!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM