zoukankan      html  css  js  c++  java
  • C#版QQTea加密

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WindowsFormsApplication1
    {
        /// <summary>
        /// 加密解密QQ消息包的工具类. 
        /// </summary>
        public static class QQCrypter
        {
            private static void code(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
            {
                if (outPos > 0)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        In[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
                    }
                }
                uint[] formattedKey = FormatKey(key);
                uint y = ConvertByteArrayToUInt(In, outOffset + outPos);
                uint z = ConvertByteArrayToUInt(In, outOffset + outPos + 4);
                uint sum = 0;
                uint delta = 0x9e3779b9;
                uint n = 16;
    
                while (n-- > 0)
                {
                    sum += delta;
                    y += ((z << 4) + formattedKey[0]) ^ (z + sum) ^ ((z >> 5) + formattedKey[1]);
                    z += ((y << 4) + formattedKey[2]) ^ (y + sum) ^ ((y >> 5) + formattedKey[3]);
                }
                Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
                Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 4, 4);
                if (inPos > 0)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        Out[outOffset + outPos + i] = (byte)(Out[outOffset + outPos + i] ^ In[inOffset + inPos + i - 8]);
                    }
                }
            }
    
            private static void decode(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
            {
                if (outPos > 0)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        Out[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
                    }
                }
                else
                {
                    Array.Copy(In, inOffset, Out, outOffset, 8);
                }
                uint[] formattedKey = FormatKey(key);
                uint y = ConvertByteArrayToUInt(Out, outOffset + outPos);
                uint z = ConvertByteArrayToUInt(Out, outOffset + outPos + 4);
                uint sum = 0xE3779B90;
                uint delta = 0x9e3779b9;
                uint n = 16;
    
                while (n-- > 0)
                {
                    z -= ((y << 4) + formattedKey[2]) ^ (y + sum) ^ ((y >> 5) + formattedKey[3]);
                    y -= ((z << 4) + formattedKey[0]) ^ (z + sum) ^ ((z >> 5) + formattedKey[1]);
                    sum -= delta;
                }
                Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
                Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 4, 4);
            }
    
            /**/
            /// <summary>
            /// 解密
            /// </summary>
            /// <param name="In">密文</param>
            /// <param name="offset">密文开始的位置</param>
            /// <param name="len">密文长度</param>
            /// <param name="key">密钥</param>
            /// <returns>返回明文</returns>
            public static byte[] Decrypt(byte[] In, int offset, int len, byte[] key)
            {
                // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
                if ((len % 8 != 0) || (len < 16))
                {
                    return null;
                }
                byte[] Out = new byte[len];
                for (int i = 0; i < len; i += 8)
                {
                    decode(In, offset, i, Out, 0, i, key);
                }
                for (int i = 8; i < len; i++)
                {
                    Out[i] = (byte)(Out[i] ^ In[offset + i - 8]);
                }
                int pos = Out[0] & 0x07;
                len = len - pos - 10;
                byte[] res = new byte[len];
                Array.Copy(Out, pos + 3, res, 0, len);
                return res;
            }
    
            public static byte[] Encrypt(byte[] In, int offset, int len, byte[] key)
            {
                // 计算头部填充字节数
                int pos = (len + 10) % 8;
                if (pos != 0)
                {
                    pos = 8 - pos;
                }
                byte[] plain = new byte[len + pos + 10];
                Random Rnd = new Random();
                plain[0] = (byte)((Rnd.Next() & 0xF8) | pos);
                for (int i = 1; i < pos + 3; i++)
                {
                    plain[i] = (byte)(Rnd.Next() & 0xFF);
                }
                Array.Copy(In, 0, plain, pos + 3, len);
                for (int i = pos + 3 + len; i < plain.Length; i++)
                {
                    plain[i] = 0x0;
                }
                // 定义输出流
                byte[] outer = new byte[len + pos + 10];
                for (int i = 0; i < outer.Length; i += 8)
                {
                    code(plain, 0, i, outer, 0, i, key);
                }
                return outer;
            }
    
            private static uint[] FormatKey(byte[] key)
            {
                if (key.Length == 0)
                {
                    throw new ArgumentException("Key must be between 1 and 16 characters in length");
                }
                byte[] refineKey = new byte[16];
                if (key.Length < 16)
                {
                    Array.Copy(key, 0, refineKey, 0, key.Length);
                    for (int k = key.Length; k < 16; k++)
                    {
                        refineKey[k] = 0x20;
                    }
                }
                else
                {
                    Array.Copy(key, 0, refineKey, 0, 16);
                }
                uint[] formattedKey = new uint[4];
                int j = 0;
                for (int i = 0; i < refineKey.Length; i += 4)
                {
                    formattedKey[j++] = ConvertByteArrayToUInt(refineKey, i);
                }
                return formattedKey;
            }
    
            private static byte[] ConvertUIntToByteArray(uint v)
            {
                byte[] result = new byte[4];
                result[0] = (byte)((v >> 24) & 0xFF);
                result[1] = (byte)((v >> 16) & 0xFF);
                result[2] = (byte)((v >> 8) & 0xFF);
                result[3] = (byte)((v >> 0) & 0xFF);
                return result;
            }
    
            private static uint ConvertByteArrayToUInt(byte[] v, int offset)
            {
                if (offset + 4 > v.Length)
                {
                    return 0;
                }
                uint output;
                output = (uint)(v[offset] << 24);
                output |= (uint)(v[offset + 1] << 16);
                output |= (uint)(v[offset + 2] << 8);
                output |= (uint)(v[offset + 3] << 0);
                return output;
            }
        }
    
    
    }
  • 相关阅读:
    第60天:Requests的基本用法
    第59天: Web 开发 Django 模型
    第58天: Web 开发 Django 入门
    第57天: Flask 用户登录 Flask-Login
    第56天:urllib 包基本使用
    第55天:爬虫的介绍
    第54天:Python 多线程 Event
    第53天: Python 线程池
    第52天:python multiprocessing模块
    第51天: Python Queue 入门
  • 原文地址:https://www.cnblogs.com/yeye518/p/3368406.html
Copyright © 2011-2022 走看看