C#版本的discuz authcode函数
时间:2010-09-06 来源:切忌浮躁
根据网上流传甚广的一个版本修改,修正了设置加密串过期时间expiry没有效果的问题。
1 using System;2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Text;
6
7 namespace API.Common
8 {
9 public enum DiscuzAuthcodeMode { Encode, Decode };
10
11 /// <summary>
12 /// C#版本 discuz authcode函数。根据网上版本修正设置expiry无效问题。by pwg17
13 /// </summary>
14 public class Authcode
15 {
16 private static Encoding encoding = Encoding.GetEncoding("gbk");
17
18 public Authcode()
19 {
20 }
21
22 /// <summary>
23 /// 从字符串的指定位置截取指定长度的子字符串
24 /// </summary>
25 /// <param name="str">原字符串</param>
26 /// <param name="startIndex">子字符串的起始位置</param>
27 /// <param name="length">子字符串的长度</param>
28 /// <returns>子字符串</returns>
29 private static string CutString(string str, int startIndex, int length)
30 {
31 if (startIndex >= 0)
32 {
33 if (length < 0)
34 {
35 length = length * -1;
36 if (startIndex - length < 0)
37 {
38 length = startIndex;
39 startIndex = 0;
40 }
41 else
42 {
43 startIndex = startIndex - length;
44 }
45 }
46
47 if (startIndex > str.Length)
48 {
49 return "";
50 }
51 }
52 else
53 {
54 if (length < 0)
55 {
56 return "";
57 }
58 else
59 {
60 if (length + startIndex > 0)
61 {
62 length = length + startIndex;
63 startIndex = 0;
64 }
65 else
66 {
67 return "";
68 }
69 }
70 }
71
72 if (str.Length - startIndex < length)
73 {
74 length = str.Length - startIndex;
75 }
76
77 return str.Substring(startIndex, length);
78 }
79
80 /// <summary>
81 /// 从字符串的指定位置开始截取到字符串结尾的了符串
82 /// </summary>
83 /// <param name="str">原字符串</param>
84 /// <param name="startIndex">子字符串的起始位置</param>
85 /// <returns>子字符串</returns>
86 private static string CutString(string str, int startIndex)
87 {
88 return CutString(str, startIndex, str.Length);
89 }
90
91 /// <summary>
92 /// MD5函数
93 /// </summary>
94 /// <param name="str">原始字符串</param>
95 /// <returns>MD5结果</returns>
96 public static string MD5(string str)
97 {
98 byte[] b = encoding.GetBytes(str);
99 b = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(b);
100 string ret = "";
101 for (int i = 0; i < b.Length; i++)
102 {
103 ret += b[i].ToString("x").PadLeft(2, '0');
104 }
105 return ret;
106 }
107
108 /// <summary>
109 /// 用于 RC4 处理密码
110 /// </summary>
111 /// <param name="pass">密码字串</param>
112 /// <param name="kLen">密钥长度,一般为 256</param>
113 /// <returns></returns>
114 private static Byte[] GetKey(Byte[] pass, Int32 kLen)
115 {
116 Byte[] mBox = new Byte[kLen];
117
118 for (Int64 i = 0; i < kLen; i++)
119 {
120 mBox[i] = (Byte)i;
121 }
122 Int64 j = 0;
123 for (Int64 i = 0; i < kLen; i++)
124 {
125 j = (j + mBox[i] + pass[i % pass.Length]) % kLen;
126 Byte temp = mBox[i];
127 mBox[i] = mBox[j];
128 mBox[j] = temp;
129 }
130 return mBox;
131 }
132
133 /// <summary>
134 /// 生成随机字符
135 /// </summary>
136 /// <param name="lens">随机字符长度</param>
137 /// <returns>随机字符</returns>
138 private static string RandomString(int lens)
139 {
140 char[] CharArray = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
141 int clens = CharArray.Length;
142 string sCode = "";
143 Random random = new Random();
144 for (int i = 0; i < lens; i++)
145 {
146 sCode += CharArray[random.Next(clens)];
147 }
148 return sCode;
149 }
150
151 /// <summary>
152 /// 使用 authcode 方法对字符串加密
153 /// </summary>
154 /// <param name="source">原始字符串</param>
155 /// <param name="key">密钥</param>
156 /// <param name="expiry">加密字串有效时间,单位是秒</param>
157 /// <returns>加密结果</returns>
158 public static string DiscuzAuthcodeEncode(string source, string key, int expiry)
159 {
160 return DiscuzAuthcode(source, key, DiscuzAuthcodeMode.Encode, expiry);
161
162 }
163
164 /// <summary>
165 /// 使用 Discuz authcode 方法对字符串加密
166 /// </summary>
167 /// <param name="source">原始字符串</param>
168 /// <param name="key">密钥</param>
169 /// <returns>加密结果</returns>
170 public static string DiscuzAuthcodeEncode(string source, string key)
171 {
172 return DiscuzAuthcode(source, key, DiscuzAuthcodeMode.Encode, 0);
173
174 }
175
176 /// <summary>
177 /// 使用 Discuz authcode 方法对字符串解密
178 /// </summary>
179 /// <param name="source">原始字符串</param>
180 /// <param name="key">密钥</param>
181 /// <returns>解密结果</returns>
182 public static string DiscuzAuthcodeDecode(string source, string key)
183 {
184 return DiscuzAuthcode(source, key, DiscuzAuthcodeMode.Decode, 0);
185
186 }
187
188 /// <summary>
189 /// 使用 变形的 rc4 编码方法对字符串进行加密或者解密
190 /// </summary>
191 /// <param name="source">原始字符串</param>
192 /// <param name="key">密钥</param>
193 /// <param name="operation">操作 加密还是解密</param>
194 /// <param name="expiry">密文有效期, 加密时候有效, 单 位 秒,0 为永久有效</param>
195 /// <returns>加密或者解密后的字符串</returns>
196 private static string DiscuzAuthcode(string source, string key, DiscuzAuthcodeMode operation, int expiry)
197 {
198 if (source == null || key == null)
199 {
200 return "";
201 }
202
203 int ckey_length = 4;
204 string keya, keyb, keyc, cryptkey, result;
205
206 key = MD5(key);
207 keya = MD5(CutString(key, 0, 16));
208 keyb = MD5(CutString(key, 16, 16));
209 keyc = ckey_length > 0 ? (operation == DiscuzAuthcodeMode.Decode ? CutString(source, 0, ckey_length) : RandomString(ckey_length)) : "";
210
211 cryptkey = keya + MD5(keya + keyc);
212
213 if (operation == DiscuzAuthcodeMode.Decode)
214 {
215 byte[] temp;
216 try
217 {
218 temp = System.Convert.FromBase64String(CutString(source, ckey_length));
219 }
220 catch
221 {
222 try
223 {
224 temp = System.Convert.FromBase64String(CutString(source + "=", ckey_length));
225 }
226 catch
227 {
228 try
229 {
230 temp = System.Convert.FromBase64String(CutString(source + "==", ckey_length));
231 }
232 catch
233 {
234 return "";
235 }
236 }
237 }
238
239 result = encoding.GetString(RC4(temp, cryptkey));
240
241 long timestamp = long.Parse(CutString(result, 0, 10));
242
243 if ((timestamp == 0 || timestamp - UnixTimestamp() > 0) && CutString(result, 10, 16) == CutString(MD5(CutString(result, 26) + keyb), 0, 16))
244 {
245 return CutString(result, 26);
246 }
247 else
248 {
249 return "";
250 }
251 }
252 else
253 {
254 source = (expiry == 0 ? "0000000000" : (expiry + UnixTimestamp()).ToString()) + CutString(MD5(source + keyb), 0, 16) + source;
255 byte[] temp = RC4(encoding.GetBytes(source), cryptkey);
256 return keyc + System.Convert.ToBase64String(temp);
257 }
258 }
259
260 /// <summary>
261 /// RC4 原始算法
262 /// </summary>
263 /// <param name="input">原始字串数组</param>
264 /// <param name="pass">密钥</param>
265 /// <returns>处理后的字串数组</returns>
266 private static Byte[] RC4(Byte[] input, String pass)
267 {
268 if (input == null || pass == null) return null;
269
270 byte[] output = new Byte[input.Length];
271 byte[] mBox = GetKey(encoding.GetBytes(pass), 256);
272
273 // 加密
274 Int64 i = 0;
275 Int64 j = 0;
276 for (Int64 offset = 0; offset < input.Length; offset++)
277 {
278 i = (i + 1) % mBox.Length;
279 j = (j + mBox[i]) % mBox.Length;
280 Byte temp = mBox[i];
281 mBox[i] = mBox[j];
282 mBox[j] = temp;
283 Byte a = input[offset];
284 //Byte b = mBox[(mBox[i] + mBox[j] % mBox.Length) % mBox.Length];
285 // mBox[j] 一定比 mBox.Length 小,不需要在取模
286 Byte b = mBox[(mBox[i] + mBox[j]) % mBox.Length];
287 output[offset] = (Byte)((Int32)a ^ (Int32)b);
288 }
289
290 return output;
291 }
292
293
294 private static string AscArr2Str(byte[] b)
295 {
296 return System.Text.UnicodeEncoding.Unicode.GetString(
297 System.Text.ASCIIEncoding.Convert(System.Text.Encoding.ASCII,
298 System.Text.Encoding.Unicode, b)
299 );
300 }
301
302 public static long UnixTimestamp()
303 {
304 DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
305 DateTime dtNow = DateTime.Parse(DateTime.Now.ToString());
306 TimeSpan toNow = dtNow.Subtract(dtStart);
307 string timeStamp = toNow.Ticks.ToString();
308 return long.Parse(timeStamp.Substring(0, timeStamp.Length - 7));
309 }
310
311 public static string urlencode(string str)
312 {
313 //php的urlencode不同于HttpUtility.UrlEncode
314 //return HttpUtility.UrlEncode(str);
315
316 string tmp = string.Empty;
317 string strSpecial = "_-.1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
318 for (int i = 0; i < str.Length; i++)
319 {
320 string crt = str.Substring(i, 1);
321 if (strSpecial.Contains(crt))
322 tmp += crt;
323 else
324 {
325 byte[] bts = encoding.GetBytes(crt);
326 foreach (byte bt in bts)
327 {
328 tmp += "%" + bt.ToString("X");
329 }
330 }
331 }
332 return tmp;
333 }
334
335 public static long time()
336 {
337 TimeSpan ts = new TimeSpan(System.DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks);
338 return (long)ts.TotalMilliseconds;
339 }
340 }
341 }
相关阅读 更多 +