网上找到的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的整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容
* ------- 消息填充算法 ------------
Code
1![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
2
/// 加密解密QQ消息包的工具类.
3
/// </summary>
4
public static class QQCrypter
5![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
6
private static void code(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
7![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
8
if (outPos > 0)
9![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10
for (int i = 0; i < 8; i++)
11![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
while (n-- > 0)
23![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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 + 4, 4);
30
if (inPos > 0)
31![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
for (int i = 0; i < 8; i++)
33![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
34
Out[outOffset + outPos + i] = (byte)(Out[outOffset + outPos + i] ^ In[inOffset + inPos + i - 8]);
35
}
36
}
37
}
38![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
private static void decode(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
40![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
41
if (outPos > 0)
42![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43
for (int i = 0; i < 8; i++)
44![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
45
Out[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
46
}
47
}
48
else
49![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59
while (n-- > 0)
60![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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 + 4, 4);
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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)
78![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
79
// 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
80
if ((len % 8 != 0) || (len < 16))
81![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
82
return null;
83
}
84
byte[] Out = new byte[len];
85
for (int i = 0; i < len; i += 8)
86![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
87
decode(In, offset, i, Out, 0, i, key);
88
}
89
for (int i = 8; i < len; i++)
90![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
100
public static byte[] Encrypt(byte[] In, int offset, int len, byte[] key)
101![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
102
// 计算头部填充字节数
103
int pos = (len + 10) % 8;
104
if (pos != 0)
105![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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++)
111![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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++)
116![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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)
122![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
123
code(plain, 0, i, outer, 0, i, key);
124
}
125
return outer;
126
}
127![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
128
private static uint[] FormatKey(byte[] key)
129![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
130
if (key.Length == 0)
131![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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)
136![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
137
Array.Copy(key, 0, refineKey, 0, key.Length);
138
for (int k = key.Length; k < 16; k++)
139![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
140
refineKey[k] = 0x20;
141
}
142
}
143
else
144![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
145
Array.Copy(key, 0, refineKey, 0, 16);
146
}
147
uint[] formattedKey = new uint[4];
148
int j = 0;
149
for (int i = 0; i < refineKey.Length; i += 4)
150![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
151
formattedKey[j++] = ConvertByteArrayToUInt(refineKey, i);
152
}
153
return formattedKey;
154
}
155![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
156
private static byte[] ConvertUIntToByteArray(uint v)
157![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
166
private static uint ConvertByteArrayToUInt(byte[] v, int offset)
167![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
168
if (offset + 4 > v.Length)
169![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.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![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
180
}
181