QQ协议TEA加密解密代码 C#

     网上找到的qq协议的TEA加密和解密说明如下: 也有很多源代码,但是感觉上代码比较复杂,不容易看。我用C#重写了下。 基于2008协议

     * QQ消息的加密算法是一个16次的迭代过程,并且是反馈的,每一个加密单元是8字节,输出也是8字节,密钥是16字节

     * 我们以prePlain表示前一个明文块,plain表示当前明文块,crypt表示当前明文块加密得到的密文块,preCrypt表示前一个密文块
     * f表示加密算法,d表示解密算法 那么从plain得到crypt的过程是:
     *       crypt = f(plain ^ preCrypt) ^ prePlain
     * 所以,从crypt得到plain的过程自然是
     *       plain = d(crypt ^ prePlain) ^ preCrypt
     * 此外,算法有它的填充机制,其会在明文前和明文后分别填充一定的字节数,以保证明文长度是8字节的倍数
     * 填充的字节数与原始明文长度有关,填充的方法是:
     *
     *      ------- 消息填充算法 -----------
     *      a = (明文长度 + 10) mod 8
     *      if(a 不等于 0) a = 8 - a;
     *      b = 随机数 & 0xF8 | a;              这个的作用是把a的值保存了下来
     *      plain[0] = b;                   然后把b做为明文的第0个字节,这样第0个字节就保存了a的信息,这个信息在解密时就要用来找到真正明文的起始位置
     *      plain[1 至 a+2] = 随机数 & 0xFF;    这里用随机数填充明文的第1到第a+2个字节
     *      plain[a+3 至 a+3+明文长度-1] = 明文; 从a+3字节开始才是真正的明文
     *      plain[a+3+明文长度, 最后] = 0;       在最后,填充0,填充到总长度为8的整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容

     *      ------- 消息填充算法 ------------

 

ContractedBlock.gif ExpandedBlockStart.gif Code
  1ExpandedBlockStart.gifContractedBlock.gif    /**//// <summary>
  2    /// 加密解密QQ消息包的工具类. 
  3    /// </summary>

  4    public static class QQCrypter
  5ExpandedBlockStart.gifContractedBlock.gif    {
  6        private static void code(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
  7ExpandedSubBlockStart.gifContractedSubBlock.gif        {
  8            if (outPos > 0)
  9ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 10                for (int i = 0; i < 8; i++)
 11ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 12                    In[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
 13                }

 14            }

 15            uint[] formattedKey = FormatKey(key);
 16            uint y = ConvertByteArrayToUInt(In, outOffset + outPos);
 17            uint z = ConvertByteArrayToUInt(In, outOffset + outPos + 4);
 18            uint sum = 0;
 19            uint delta = 0x9e3779b9;
 20            uint n = 16;
 21
 22            while (n-- > 0)
 23ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 24                sum += delta;
 25                y += ((z << 4+ formattedKey[0]) ^ (z + sum) ^ ((z >> 5+ formattedKey[1]);
 26                z += ((y << 4+ formattedKey[2]) ^ (y + sum) ^ ((y >> 5+ formattedKey[3]);
 27            }

 28            Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
 29            Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 44);
 30            if (inPos > 0)
 31ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 32                for (int i = 0; i < 8; i++)
 33ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 34                    Out[outOffset + outPos + i] = (byte)(Out[outOffset + outPos + i] ^ In[inOffset + inPos + i - 8]);
 35                }

 36            }

 37        }

 38
 39        private static void decode(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
 40ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 41            if (outPos > 0)
 42ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 43                for (int i = 0; i < 8; i++)
 44ExpandedSubBlockStart.gifContractedSubBlock.gif                {
 45                    Out[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
 46                }

 47            }

 48            else
 49ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 50                Array.Copy(In, inOffset, Out, outOffset, 8);
 51            }

 52            uint[] formattedKey = FormatKey(key);
 53            uint y = ConvertByteArrayToUInt(Out, outOffset + outPos);
 54            uint z = ConvertByteArrayToUInt(Out, outOffset + outPos + 4);
 55            uint sum = 0xE3779B90;
 56            uint delta = 0x9e3779b9;
 57            uint n = 16;
 58
 59            while (n-- > 0)
 60ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 61                z -= ((y << 4+ formattedKey[2]) ^ (y + sum) ^ ((y >> 5+ formattedKey[3]);
 62                y -= ((z << 4+ formattedKey[0]) ^ (z + sum) ^ ((z >> 5+ formattedKey[1]);
 63                sum -= delta;
 64            }

 65            Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
 66            Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 44);
 67        }

 68
 69ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 70        /// 解密
 71        /// </summary>
 72        /// <param name="In">密文</param>
 73        /// <param name="offset">密文开始的位置</param>
 74        /// <param name="len">密文长度</param>
 75        /// <param name="key">密钥</param>
 76        /// <returns>返回明文</returns>

 77        public static byte[] Decrypt(byte[] In, int offset, int len, byte[] key)
 78ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 79            // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
 80            if ((len % 8 != 0|| (len < 16))
 81ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 82                return null;
 83            }

 84            byte[] Out = new byte[len];
 85            for (int i = 0; i < len; i += 8)
 86ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 87                decode(In, offset, i, Out, 0, i, key);
 88            }

 89            for (int i = 8; i < len; i++)
 90ExpandedSubBlockStart.gifContractedSubBlock.gif            {
 91                Out[i] = (byte)(Out[i] ^ In[offset + i - 8]);
 92            }

 93            int pos = Out[0& 0x07;
 94            len = len - pos - 10;
 95            byte[] res = new byte[len];
 96            Array.Copy(Out, pos + 3, res, 0, len);
 97            return res;
 98        }

 99
100        public static byte[] Encrypt(byte[] In, int offset, int len, byte[] key)
101ExpandedSubBlockStart.gifContractedSubBlock.gif        {
102            // 计算头部填充字节数
103            int pos = (len + 10% 8;
104            if (pos != 0)
105ExpandedSubBlockStart.gifContractedSubBlock.gif            {
106                pos = 8 - pos;
107            }

108            byte[] plain = new byte[len + pos + 10];
109            plain[0= (byte)((Rnd.Next() & 0xF8| pos);
110            for (int i = 1; i < pos + 3; i++)
111ExpandedSubBlockStart.gifContractedSubBlock.gif            {
112                plain[i] = (byte)(Rnd.Next() & 0xFF);
113            }

114            Array.Copy(In, 0, plain, pos + 3, len);
115            for (int i = pos + 3 + len; i < plain.Length; i++)
116ExpandedSubBlockStart.gifContractedSubBlock.gif            {
117                plain[i] = 0x0;
118            }

119            // 定义输出流
120            byte[] outer = new byte[len + pos + 10];
121            for (int i = 0; i < outer.Length; i += 8)
122ExpandedSubBlockStart.gifContractedSubBlock.gif            {
123                code(plain, 0, i, outer, 0, i, key);
124            }

125            return outer;
126        }

127
128        private static uint[] FormatKey(byte[] key)
129ExpandedSubBlockStart.gifContractedSubBlock.gif        {
130            if (key.Length == 0)
131ExpandedSubBlockStart.gifContractedSubBlock.gif            {
132                throw new ArgumentException("Key must be between 1 and 16 characters in length");
133            }

134            byte[] refineKey = new byte[16];
135            if (key.Length < 16)
136ExpandedSubBlockStart.gifContractedSubBlock.gif            {
137                Array.Copy(key, 0, refineKey, 0, key.Length);
138                for (int k = key.Length; k < 16; k++)
139ExpandedSubBlockStart.gifContractedSubBlock.gif                {
140                    refineKey[k] = 0x20;
141                }

142            }

143            else
144ExpandedSubBlockStart.gifContractedSubBlock.gif            {
145                Array.Copy(key, 0, refineKey, 016);
146            }

147            uint[] formattedKey = new uint[4];
148            int j = 0;
149            for (int i = 0; i < refineKey.Length; i += 4)
150ExpandedSubBlockStart.gifContractedSubBlock.gif            {
151                formattedKey[j++= ConvertByteArrayToUInt(refineKey, i);
152            }

153            return formattedKey;
154        }

155
156        private static byte[] ConvertUIntToByteArray(uint v)
157ExpandedSubBlockStart.gifContractedSubBlock.gif        {
158            byte[] result = new byte[4];
159            result[0= (byte)((v >> 24& 0xFF);
160            result[1= (byte)((v >> 16& 0xFF);
161            result[2= (byte)((v >> 8& 0xFF);
162            result[3= (byte)((v >> 0& 0xFF);
163            return result;
164        }

165
166        private static uint ConvertByteArrayToUInt(byte[] v, int offset)
167ExpandedSubBlockStart.gifContractedSubBlock.gif        {
168            if (offset + 4 > v.Length)
169ExpandedSubBlockStart.gifContractedSubBlock.gif            {
170                return 0;
171            }

172            uint output;
173            output = (uint)(v[offset] << 24);
174            output |= (uint)(v[offset + 1<< 16);
175            output |= (uint)(v[offset + 2<< 8);
176            output |= (uint)(v[offset + 3<< 0);
177            return output;
178        }

179
180    }

181

 

转载于:https://www.cnblogs.com/beikx/archive/2009/11/08/1598309.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值