tea qq消息

来源:互联网 发布:蓝光原盘转换mkv mac 编辑:程序博客网 时间:2024/05/20 20:05

 

代码
  1     /// <summary>
  2     /// 加密解密QQ消息包的工具类.
  3     /// </summary>
  4     public static class QQCrypter
  5     {
  6         private static Random Rnd = new Random();
  7         private static void code(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
  8         {
  9             if (outPos > 0)
 10             {
 11                 for (int i = 0; i < 8; i++)
 12                 {
 13                     In[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
 14                 }
 15             }
 16             uint[] formattedKey = FormatKey(key);
 17             uint y = ConvertByteArrayToUInt(In, outOffset + outPos);
 18             uint z = ConvertByteArrayToUInt(In, outOffset + outPos + 4);
 19             uint sum = 0;
 20             uint delta = 0x9e3779b9;
 21             uint n = 16;
 22 
 23             while (n-- > 0)
 24             {
 25                 sum += delta;
 26                 y += ((z << 4+ formattedKey[0]) ^ (z + sum) ^ ((z >> 5+ formattedKey[1]);
 27                 z += ((y << 4+ formattedKey[2]) ^ (y + sum) ^ ((y >> 5+ formattedKey[3]);
 28             }
 29             Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
 30             Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 44);
 31             if (inPos > 0)
 32             {
 33                 for (int i = 0; i < 8; i++)
 34                 {
 35                     Out[outOffset + outPos + i] = (byte)(Out[outOffset + outPos + i] ^ In[inOffset + inPos + i - 8]);
 36                 }
 37             }
 38         }
 39 
 40         private static void decode(byte[] In, int inOffset, int inPos, byte[] Out, int outOffset, int outPos, byte[] key)
 41         {
 42             if (outPos > 0)
 43             {
 44                 for (int i = 0; i < 8; i++)
 45                 {
 46                     Out[outOffset + outPos + i] = (byte)(In[inOffset + inPos + i] ^ Out[outOffset + outPos + i - 8]);
 47                 }
 48             }
 49             else
 50             {
 51                 Array.Copy(In, inOffset, Out, outOffset, 8);
 52             }
 53             uint[] formattedKey = FormatKey(key);
 54             uint y = ConvertByteArrayToUInt(Out, outOffset + outPos);
 55             uint z = ConvertByteArrayToUInt(Out, outOffset + outPos + 4);
 56             uint sum = 0xE3779B90;
 57             uint delta = 0x9e3779b9;
 58             uint n = 16;
 59 
 60             while (n-- > 0)
 61             {
 62                 z -= ((y << 4+ formattedKey[2]) ^ (y + sum) ^ ((y >> 5+ formattedKey[3]);
 63                 y -= ((z << 4+ formattedKey[0]) ^ (z + sum) ^ ((z >> 5+ formattedKey[1]);
 64                 sum -= delta;
 65             }
 66             Array.Copy(ConvertUIntToByteArray(y), 0, Out, outOffset + outPos, 4);
 67             Array.Copy(ConvertUIntToByteArray(z), 0, Out, outOffset + outPos + 44);
 68         }
 69 
 70         /// <summary>
 71         /// 解密
 72          /// </summary>
 73         /// <param name="In">密文</param>
 74         /// <param name="offset">密文开始的位置</param>
 75         /// <param name="len">密文长度</param>
 76         /// <param name="key">密钥</param>
 77         /// <returns>返回明文</returns>
 78         public static byte[] Decrypt(byte[] In, int offset, int len, byte[] key)
 79         {
 80             // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
 81             if ((len % 8 != 0|| (len < 16))
 82             {
 83                 return null;
 84             }
 85             byte[] Out = new byte[len];
 86             for (int i = 0; i < len; i += 8)
 87             {
 88                 decode(In, offset, i, Out, 0, i, key);
 89             }
 90             for (int i = 8; i < len; i++)
 91             {
 92                 Out[i] = (byte)(Out[i] ^ In[offset + i - 8]);
 93             }
 94             int pos = Out[0& 0x07;
 95             len = len - pos - 10;
 96             byte[] res = new byte[len];
 97             Array.Copy(Out, pos + 3, res, 0, len);
 98             return res;
 99         }
100 
101         /// <summary>
102         /// 加密
103          /// </summary>
104         /// <param name="In">明文</param>
105         /// <param name="offset">明文开始的位置</param>
106         /// <param name="len">明文长度</param>
107         /// <param name="key">密钥</param>
108         /// <returns>返回密文</returns>
109         public static byte[] Encrypt(byte[] In, int offset, int len, byte[] key)
110         {
111             // 计算头部填充字节数
112             int pos = (len + 10% 8;
113             if (pos != 0)
114             {
115                 pos = 8 - pos;
116             }
117             byte[] plain = new byte[len + pos + 10];
118             plain[0= (byte)((Rnd.Next() & 0xF8| pos);
119             for (int i = 1; i < pos + 3; i++)
120             {
121                 plain[i] = (byte)(Rnd.Next() & 0xFF);
122             }
123             Array.Copy(In, 0, plain, pos + 3, len);
124             for (int i = pos + 3 + len; i < plain.Length; i++)
125             {
126                 plain[i] = 0x0;
127             }
128             // 定义输出流
129               byte[] outer = new byte[len + pos + 10];
130             for (int i = 0; i < outer.Length; i += 8)
131             {
132                 code(plain, 0, i, outer, 0, i, key);
133             }
134             return outer;
135         }
136 
137         private static uint[] FormatKey(byte[] key)
138         {
139             if (key.Length == 0)
140             {
141                 throw new ArgumentException("Key must be between 1 and 16 characters in length");
142             }
143             byte[] refineKey = new byte[16];
144             if (key.Length < 16)
145             {
146                 Array.Copy(key, 0, refineKey, 0, key.Length);
147                 for (int k = key.Length; k < 16; k++)
148                 {
149                     refineKey[k] = 0x20;
150                 }
151             }
152             else
153             {
154                 Array.Copy(key, 0, refineKey, 016);
155             }
156             uint[] formattedKey = new uint[4];
157             int j = 0;
158             for (int i = 0; i < refineKey.Length; i += 4)
159             {
160                 formattedKey[j++= ConvertByteArrayToUInt(refineKey, i);
161             }
162             return formattedKey;
163         }
164 
165         private static byte[] ConvertUIntToByteArray(uint v)
166         {
167             byte[] result = new byte[4];
168             result[0= (byte)((v >> 24& 0xFF);
169             result[1= (byte)((v >> 16& 0xFF);
170             result[2= (byte)((v >> 8& 0xFF);
171             result[3= (byte)((v >> 0& 0xFF);
172             return result;
173         }
174 
175         private static uint ConvertByteArrayToUInt(byte[] v, int offset)
176         {
177             if (offset + 4 > v.Length)
178             {
179                 return 0;
180             }
181             uint output;
182             output = (uint)(v[offset] << 24);
183             output |= (uint)(v[offset + 1<< 16);
184             output |= (uint)(v[offset + 2<< 8);
185             output |= (uint)(v[offset + 3<< 0);
186             return output;
187         }
188     }

 

对外只留了两个方法用于加密和解密, 有兴趣的童鞋研究研究, 结果告诉我哦.

我找个两个版本的, 上面那个是最终使用通过的, 还有一个版本的感觉明显不对, 因为加密的时候貌似没有产生随机数的样子, 每次加密过后的密文都相同, 这我很想不通, 所以更放弃了对那段代码的研究. 后来自己尝试改写Java版的, 无功而返.

下面附Java版的代码, 带部分注释(网上找的).

 

代码
  1 package mobi.bbase.ahome.utils;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.util.Random;
  5 
  6 
  7 /**
  8  * 加密解密QQ消息的工具类. QQ消息的加密算法是一个16次的迭代过程,并且是反馈的,每一个加密单元是8字节,输出也是8字节,密钥是16字节
  9  * 我们以prePlain表示前一个明文块,plain表示当前明文块,crypt表示当前明文块加密得到的密文块,preCrypt表示前一个密文块
 10  * f表示加密算法,d表示解密算法 那么从plain得到crypt的过程是: crypt = f(plain &circ; preCrypt) &circ;
 11  * prePlain 所以,从crypt得到plain的过程自然是 plain = d(crypt &circ; prePlain) &circ;
 12  * preCrypt 此外,算法有它的填充机制,其会在明文前和明文后分别填充一定的字节数,以保证明文长度是8字节的倍数
 13  * 填充的字节数与原始明文长度有关,填充的方法是:
 14  * 
 15  * <pre>
 16  * <code>
 17  * 
 18  *      ------- 消息填充算法 ----------- 
 19  *      a = (明文长度 + 10) mod 8
 20  *      if(a 不等于 0) a = 8 - a;
 21  *      b = 随机数 &amp; 0xF8 | a;              这个的作用是把a的值保存了下来
 22  *      plain[0] = b;                   然后把b做为明文的第0个字节,这样第0个字节就保存了a的信息,这个信息在解密时就要用来找到真正明文的起始位置
 23  *      plain[1 至 a+2] = 随机数 &amp; 0xFF;    这里用随机数填充明文的第1到第a+2个字节
 24  *      plain[a+3 至 a+3+明文长度-1] = 明文; 从a+3字节开始才是真正的明文
 25  *      plain[a+3+明文长度, 最后] = 0;       在最后,填充0,填充到总长度为8的整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容
 26  *      ------- 消息填充算法 ------------
 27  *   
 28  * </code>
 29  * </pre>
 30  * 
 31  * @author luma
 32  * @author notXX
 33  */
 34 public class Crypter {
 35     // 指向当前的明文块
 36     private byte[] plain;
 37     // 这指向前面一个明文块
 38     private byte[] prePlain;
 39     // 输出的密文或者明文
 40     private byte[] out;
 41     // 当前加密的密文位置和上一次加密的密文块位置,他们相差8
 42     private int crypt, preCrypt;
 43     // 当前处理的加密解密块的位置
 44     private int pos;     
 45     // 填充数
 46     private int padding;
 47     // 密钥
 48     private byte[] key;
 49     // 用于加密时,表示当前是否是第一个8字节块,因为加密算法是反馈的
 50     // 但是最开始的8个字节没有反馈可用,所有需要标明这种情况
 51     private boolean header = true;
 52     // 这个表示当前解密开始的位置,之所以要这么一个变量是为了避免当解密到最后时
 53     // 后面已经没有数据,这时候就会出错,这个变量就是用来判断这种情况免得出错
 54     private int contextStart;
 55     // 随机数对象
 56     private static Random random = new Random();
 57     // 字节输出流
 58 private ByteArrayOutputStream baos;
 59 /**
 60 * 构造函数
 61 */
 62 public Crypter() {
 63 baos = new ByteArrayOutputStream(8);
 64 }
 65 /**
 66 * 把字节数组从offset开始的len个字节转换成一个unsigned int, 因为java里面没有unsigned,所以unsigned
 67 * int使用long表示的, 如果len大于8,则认为len等于8。如果len小于8,则高位填0 <br>
 68 * (edited by notxx) 改变了算法, 性能稍微好一点. 在我的机器上测试10000次, 原始算法花费18s, 这个算法花费12s.
 69 
 70 @param in
 71 *                   字节数组.
 72 @param offset
 73 *                   从哪里开始转换.
 74 @param len
 75 *                   转换长度, 如果len超过8则忽略后面的
 76 @return
 77 */
 78 private static long getUnsignedInt(byte[] in, int offset, int len) {
 79 long ret = 0;
 80 int end = 0;
 81 if (len > 8)
 82 end = offset + 8;
 83 else
 84 end = offset + len;
 85 for (int i = offset; i < end; i++) {
 86 ret <<= 8;
 87 ret |= in[i] & 0xff;
 88 }
 89 return (ret & 0xffffffffl| (ret >>> 32);
 90 }
 91     
 92     /**
 93      * 解密
 94      * @param in 密文
 95      * @param offset 密文开始的位置
 96      * @param len 密文长度
 97      * @param k 密钥
 98      * @return 明文
 99      */
100     public byte[] decrypt(byte[] in, int offset, int len, byte[] k) {
101     // 检查密钥
102     if(k == null)
103     return null;
104     
105         crypt = preCrypt = 0;
106         this.key = k;
107         int count;
108         byte[] m = new byte[offset + 8];
109         
110         // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
111         if((len % 8 != 0|| (len < 16)) return null;
112         // 得到消息的头部,关键是得到真正明文开始的位置,这个信息存在第一个字节里面,所以其用解密得到的第一个字节与7做与
113         prePlain = decipher(in, offset);
114         pos = prePlain[0& 0x7;
115         // 得到真正明文的长度
116         count = len - pos - 10;
117         // 如果明文长度小于0,那肯定是出错了,比如传输错误之类的,返回
118         if(count < 0return null;
119         
120         // 这个是临时的preCrypt,和加密时第一个8字节块没有prePlain一样,解密时
121         // 第一个8字节块也没有preCrypt,所有这里建一个全0的
122         for(int i = offset; i < m.length; i++)
123             m[i] = 0;
124         // 通过了上面的代码,密文应该是没有问题了,我们分配输出缓冲区
125         out = new byte[count];
126         // 设置preCrypt的位置等于0,注意目前的preCrypt位置是指向m的,因为java没有指针,所以我们在后面要控制当前密文buf的引用
127         preCrypt = 0;
128         // 当前的密文位置,为什么是8不是0呢?注意前面我们已经解密了头部信息了,现在当然该8了
129         crypt = 8;
130         // 自然这个也是8
131         contextStart = 8;
132         // 加1,和加密算法是对应的
133         pos++;
134         
135         // 开始跳过头部,如果在这个过程中满了8字节,则解密下一块
136         // 因为是解密下一块,所以我们有一个语句 m = in,下一块当然有preCrypt了,我们不再用m了
137         // 但是如果不满8,这说明了什么?说明了头8个字节的密文是包含了明文信息的,当然还是要用m把明文弄出来
138         // 所以,很显然,满了8的话,说明了头8个字节的密文除了一个长度信息有用之外,其他都是无用的填充
139         padding = 1;
140         while(padding <= 2) {
141             if(pos < 8) {
142                 pos++;
143                 padding++;
144             }
145             if(pos == 8) {
146                 m = in;
147                 if(!decrypt8Bytes(in, offset, len)) return null;
148             }
149         }
150         
151         // 这里是解密的重要阶段,这个时候头部的填充都已经跳过了,开始解密
152         // 注意如果上面一个while没有满8,这里第一个if里面用的就是原始的m,否则这个m就是in了
153         int i = 0;
154         while(count != 0) {
155             if(pos < 8) {
156                 out[i] = (byte)(m[offset + preCrypt + pos] ^ prePlain[pos]);
157                 i++;
158                 count--;
159                 pos++;
160             }
161             if(pos == 8) {
162                 m = in;
163                 preCrypt = crypt - 8;
164                 if(!decrypt8Bytes(in, offset, len)) 
165                     return null;
166             }
167         }
168         
169         // 最后的解密部分,上面一个while已经把明文都解出来了,就剩下尾部的填充了,应该全是0
170         // 所以这里有检查是否解密了之后是不是0,如果不是的话那肯定出错了,返回null
171         for(padding = 1; padding < 8; padding++) {
172             if(pos < 8) {
173                 if((m[offset + preCrypt + pos] ^ prePlain[pos]) != 0)
174                     return null;
175                 pos++;
176             }
177             if(pos == 8) {
178                 m = in;
179                 preCrypt = crypt;
180                 if(!decrypt8Bytes(in, offset, len)) 
181                     return null;
182             }
183         }
184         return out;
185     }
186     
187     /**
188      * @param in
189      *            需要被解密的密文
190      * @param inLen
191      *            密文长度
192      * @param k
193      *            密钥
194      * @return Message 已解密的消息
195      */
196     public byte[] decrypt(byte[] in, byte[] k) {   
197         return decrypt(in, 0, in.length, k);
198     }
199     
200     /**
201      * 加密
202      * @param in 明文字节数组
203      * @param offset 开始加密的偏移
204      * @param len 加密长度
205      * @param k 密钥
206      * @return 密文字节数组
207      */
208     public byte[] encrypt(byte[] in, int offset, int len, byte[] k) {
209     // 检查密钥
210     if(k == null)
211     return in;
212     
213         plain = new byte[8];
214         prePlain = new byte[8];
215         pos = 1;           
216         padding = 0
217         crypt = preCrypt = 0;
218         this.key = k;
219         header = true;
220         
221         // 计算头部填充字节数
222         pos = (len + 0x0A% 8;
223         if(pos != 0)
224             pos = 8 - pos;
225         // 计算输出的密文长度
226         out = new byte[len + pos + 10];
227         // 这里的操作把pos存到了plain的第一个字节里面
228         // 0xF8后面三位是空的,正好留给pos,因为pos是0到7的值,表示文本开始的字节位置
229         plain[0= (byte)((rand() & 0xF8| pos);
230         
231         // 这里用随机产生的数填充plain[1]到plain[pos]之间的内容
232         for(int i = 1; i <= pos; i++)
233             plain[i] = (byte)(rand() & 0xFF);
234         pos++;
235         // 这个就是prePlain,第一个8字节块当然没有prePlain,所以我们做一个全0的给第一个8字节块
236         for(int i = 0; i < 8; i++)
237             prePlain[i] = 0x0;
238         
239         // 继续填充2个字节的随机数,这个过程中如果满了8字节就加密之
240         padding = 1;
241         while(padding <= 2) {
242             if(pos < 8) {
243                 plain[pos++= (byte)(rand() & 0xFF);
244                 padding++;
245             }
246             if(pos == 8)
247                 encrypt8Bytes();
248         }
249         
250         // 头部填充完了,这里开始填真正的明文了,也是满了8字节就加密,一直到明文读完
251         int i = offset;
252         while(len > 0) {
253             if(pos < 8) {
254                 plain[pos++= in[i++];
255                 len--;
256             }
257             if(pos == 8)
258                 encrypt8Bytes();
259         }
260         
261         // 最后填上0,以保证是8字节的倍数
262         padding = 1;
263         while(padding <= 7) {
264             if(pos < 8) {
265                 plain[pos++= 0x0;
266                 padding++;
267             }
268             if(pos == 8)
269                 encrypt8Bytes();
270         }
271         
272         return out;
273     }
274 
275     /**
276      * @param in
277      *            需要加密的明文
278      * @param inLen
279      *            明文长度
280      * @param k
281      *            密钥
282      * @return Message 密文
283      */
284     public byte[] encrypt(byte[] in, byte[] k) {
285         return encrypt(in, 0, in.length, k);
286     }
287 
288     /**
289      * 加密一个8字节块
290      * 
291      * @param in
292      * 明文字节数组
293      * @return
294      * 密文字节数组
295      */
296     private byte[] encipher(byte[] in) {
297         // 迭代次数,16次
298         int loop = 0x10;
299         // 得到明文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
300         // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
301         // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与            
302         long y = getUnsignedInt(in, 04);
303         long z = getUnsignedInt(in, 44);
304         long a = getUnsignedInt(key, 04);
305         long b = getUnsignedInt(key, 44);
306         long c = getUnsignedInt(key, 84);
307         long d = getUnsignedInt(key, 124);
308         // 这是算法的一些控制变量,为什么delta是0x9E3779B9呢?
309         // 这个数是TEA算法的delta,实际是就是(sqr(5) - 1) * 2^31 (根号5,减1,再乘2的31次方)
310         long sum = 0;
311         long delta = 0x9E3779B9;
312         delta &= 0xFFFFFFFFL;
313 
314         // 开始迭代了,乱七八糟的,我也看不懂,反正和DES之类的差不多,都是这样倒来倒去
315         while (loop-- > 0) {
316             sum += delta;
317             sum &= 0xFFFFFFFFL;
318             y += ((z << 4+ a) ^ (z + sum) ^ ((z >>> 5+ b);
319             y &= 0xFFFFFFFFL;
320             z += ((y << 4+ c) ^ (y + sum) ^ ((y >>> 5+ d);
321             z &= 0xFFFFFFFFL;
322         }
323 
324         // 最后,我们输出密文,因为我用的long,所以需要强制转换一下变成int
325         baos.reset();
326         writeInt((int)y);
327         writeInt((int)z);
328         return baos.toByteArray();
329     }
330     
331     /**
332      * 解密从offset开始的8字节密文
333      * 
334      * @param in
335      * 密文字节数组
336      * @param offset
337      * 密文开始位置
338      * @return
339      * 明文
340      */
341     private byte[] decipher(byte[] in, int offset) {
342         // 迭代次数,16次
343         int loop = 0x10;
344         // 得到密文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
345         // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
346         // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
347         long y = getUnsignedInt(in, offset, 4);
348         long z = getUnsignedInt(in, offset + 44);
349         long a = getUnsignedInt(key, 04);
350         long b = getUnsignedInt(key, 44);
351         long c = getUnsignedInt(key, 84);
352         long d = getUnsignedInt(key, 124);
353         // 算法的一些控制变量,sum在这里也有数了,这个sum和迭代次数有关系
354         // 因为delta是这么多,所以sum如果是这么多的话,迭代的时候减减减,减16次,最后
355         // 得到0。反正这就是为了得到和加密时相反顺序的控制变量,这样才能解密呀~~
356         long sum = 0xE3779B90;
357         sum &= 0xFFFFFFFFL;
358         long delta = 0x9E3779B9;
359         delta &= 0xFFFFFFFFL;
360 
361         // 迭代开始了, @_@
362         while(loop-- > 0) {
363             z -= ((y << 4+ c) ^ (y + sum) ^ ((y >>> 5+ d);
364             z &= 0xFFFFFFFFL;
365             y -= ((z << 4+ a) ^ (z + sum) ^ ((z >>> 5+ b);
366             y &= 0xFFFFFFFFL;
367             sum -= delta;
368             sum &= 0xFFFFFFFFL;
369         }
370 
371         baos.reset();
372         writeInt((int)y);
373         writeInt((int)z);
374         return baos.toByteArray();
375     }
376     
377     /**
378      * 写入一个整型到输出流,高字节优先
379      * 
380      * @param t
381      */
382     private void writeInt(int t) {
383         baos.write(t >>> 24);
384         baos.write(t >>> 16);
385         baos.write(t >>> 8);
386         baos.write(t);
387     }
388     
389     /**
390      * 解密
391      * 
392      * @param in
393      * 密文
394      * @return
395      * 明文
396      */
397     private byte[] decipher(byte[] in) {
398         return decipher(in, 0);
399     }
400     
401     /**
402      * 加密8字节 
403      */
404     private void encrypt8Bytes() {
405         // 这部分完成我上面所说的 plain ^ preCrypt,注意这里判断了是不是第一个8字节块,如果是的话,那个prePlain就当作preCrypt用
406         for(pos = 0; pos < 8; pos++) {
407             if(header) 
408             plain[pos] ^= prePlain[pos];
409             else
410             plain[pos] ^= out[preCrypt + pos];
411         }
412         // 这个完成我上面说的 f(plain ^ preCrypt)
413         byte[] crypted = encipher(plain);
414         // 这个没什么,就是拷贝一下,java不像c,所以我只好这么干,c就不用这一步了
415         System.arraycopy(crypted, 0, out, crypt, 8);
416         
417         // 这个完成了 f(plain ^ preCrypt) ^ prePlain,ok,下面拷贝一下就行了
418         for(pos = 0; pos < 8; pos++)
419             out[crypt + pos] ^= prePlain[pos];
420         System.arraycopy(plain, 0, prePlain, 08);
421         
422         // 完成了加密,现在是调整crypt,preCrypt等等东西的时候了
423         preCrypt = crypt;
424         crypt += 8;      
425         pos = 0;
426         header = false;            
427     }
428 
429     /**
430      * 解密8个字节
431      * 
432      * @param in
433      * 密文字节数组
434      * @param offset
435      * 从何处开始解密
436      * @param len
437      * 密文的长度
438      * @return
439      * true表示解密成功
440      */
441     private boolean decrypt8Bytes(byte[] in , int offset, int len) {
442         // 这里第一步就是判断后面还有没有数据,没有就返回,如果有,就执行 crypt ^ prePlain
443         for(pos = 0; pos < 8; pos++) {
444             if(contextStart + pos >= len) 
445                 return true;
446             prePlain[pos] ^= in[offset + crypt + pos];
447         }
448         
449         // 好,这里执行到了 d(crypt ^ prePlain)
450         prePlain = decipher(prePlain);
451         if(prePlain == null)
452         return false;
453         
454         // 解密完成,最后一步好像没做? 
455         // 这里最后一步放到decrypt里面去做了,因为解密的步骤有点不太一样
456         // 调整这些变量的值先
457         contextStart += 8;
458         crypt += 8;
459         pos = 0;
460         return true;
461     }
462     
463     /**
464      * 这是个随机因子产生器,用来填充头部的,如果为了调试,可以用一个固定值
465      * 随机因子可以使相同的明文每次加密出来的密文都不一样
466      * 
467      * @return
468      * 随机因子
469      */
470     private int rand() {
471         return random.nextInt();
472     }
473 }

貌似比较长啊...童鞋们努力吧~~

哎呀, 头疼...