差點吐血! 這破玩意搞了N天, 終於搞定了, 但是很遺憾的是, 還是不明就裏, 暫時先把工作進行下去吧...
因爲需要跟Java版的通信, Java加密, C#的再解密, 這樣就帶來很多問題, 不過最終還是OK了.
代碼如下(那個迭代過程實在是讓我頭疼啊, 看來算法還得加強!):
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 + 4, 4);
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 + 4, 4);
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, 0, 16);
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版的代碼, 帶部分註釋(網上找的).
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 ˆ preCrypt) ˆ
11 * prePlain 所以,從crypt得到plain的過程自然是 plain = d(crypt ˆ prePlain) ˆ
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 = 隨機數 & 0xF8 | a; 這個的作用是把a的值保存了下來
22 * plain[0] = b; 然後把b做爲明文的第0個字節,這樣第0個字節就保存了a的信息,這個信息在解密時就要用來找到真正明文的起始位置
23 * plain[1 至 a+2] = 隨機數 & 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 < 0) return 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, 0, 4);
303 long z = getUnsignedInt(in, 4, 4);
304 long a = getUnsignedInt(key, 0, 4);
305 long b = getUnsignedInt(key, 4, 4);
306 long c = getUnsignedInt(key, 8, 4);
307 long d = getUnsignedInt(key, 12, 4);
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 + 4, 4);
349 long a = getUnsignedInt(key, 0, 4);
350 long b = getUnsignedInt(key, 4, 4);
351 long c = getUnsignedInt(key, 8, 4);
352 long d = getUnsignedInt(key, 12, 4);
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, 0, 8);
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 }
貌似比較長啊...童鞋們努力吧~~
哎呀, 頭疼...