很有意思的一件事情,当我想要找 Xxtea 加解密算法的时候,发现了前同事(likui318)的代码,不妨分享出来。此代码满足:
1:Xxtea支持中文;
2:支持 JS 和 C# 加解密之间的互转;
一:C#部分
class XXTEA2
{ public static string Encrypt(string source, string key) { System.Text.Encoding encoder = System.Text.Encoding.UTF8; //UTF8==>BASE64==>XXTEA==>BASE64 byte[] bytData = encoder.GetBytes(base64Encode(source)); byte[] bytKey = encoder.GetBytes(key); if (bytData.Length == 0) { return ""; } return System.Convert.ToBase64String(ToByteArray(Encrypt(ToUInt32Array(bytData, true), ToUInt32Array(bytKey, false)), false)); } public static string Decrypt(string source, string key) { if (source.Length == 0) { return ""; } // reverse System.Text.Encoding encoder = System.Text.Encoding.UTF8; byte[] bytData = System.Convert.FromBase64String(source); byte[] bytKey = encoder.GetBytes(key);return base64Decode(encoder.GetString(ToByteArray(Decrypt(ToUInt32Array(bytData, false), ToUInt32Array(bytKey, false)), true)));
}private static UInt32[] Encrypt(UInt32[] v, UInt32[] k)
{ Int32 n = v.Length - 1; if (n < 1) { return v; } if (k.Length < 4) { UInt32[] Key = new UInt32[4]; k.CopyTo(Key, 0); k = Key; } UInt32 z = v[n], y = v[0], delta = 0x9E3779B9, sum = 0, e; Int32 p, q = 6 + 52 / (n + 1); while (q-- > 0) { sum = unchecked(sum + delta); e = sum >> 2 & 3; for (p = 0; p < n; p++) { y = v[p + 1]; z = unchecked(v[p] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)); } y = v[0]; z = unchecked(v[n] += (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)); } return v; }private static UInt32[] Decrypt(UInt32[] v, UInt32[] k)
{ Int32 n = v.Length - 1; if (n < 1) { return v; } if (k.Length < 4) { UInt32[] Key = new UInt32[4]; k.CopyTo(Key, 0); k = Key; } UInt32 z = v[n], y = v[0], delta = 0x9E3779B9, sum, e; Int32 p, q = 6 + 52 / (n + 1); sum = unchecked((UInt32)(q * delta)); while (sum != 0) { e = sum >> 2 & 3; for (p = n; p > 0; p--) { z = v[p - 1]; y = unchecked(v[p] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)); } z = v[n]; y = unchecked(v[0] -= (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)); sum = unchecked(sum - delta); } return v; }private static UInt32[] ToUInt32Array(Byte[] Data, Boolean IncludeLength)
{ Int32 n = (((Data.Length & 3) == 0) ? (Data.Length >> 2) : ((Data.Length >> 2) + 1)); UInt32[] Result; if (IncludeLength) { Result = new UInt32[n + 1]; Result[n] = (UInt32)Data.Length; } else { Result = new UInt32[n]; } n = Data.Length; for (Int32 i = 0; i < n; i++) { Result[i >> 2] |= (UInt32)Data[i] << ((i & 3) << 3); } return Result; }private static Byte[] ToByteArray(UInt32[] Data, Boolean IncludeLength)
{ Int32 n; if (IncludeLength) { n = (Int32)Data[Data.Length - 1]; } else { n = Data.Length << 2; } Byte[] Result = new Byte[n]; for (Int32 i = 0; i < n; i++) { Result[i] = (Byte)(Data[i >> 2] >> ((i & 3) << 3)); } return Result; }public static string base64Decode(string data)
{ try { var encoder = System.Text.Encoding.UTF8;byte[] todecode_byte = Convert.FromBase64String(data);
return encoder.GetString(todecode_byte); } catch (Exception e) { throw new Exception("Error in base64Decode" + e.Message); } }public static string base64Encode(string data)
{ try { byte[] encData_byte = new byte[data.Length]; encData_byte = System.Text.Encoding.UTF8.GetBytes(data); string encodedData = Convert.ToBase64String(encData_byte); return encodedData; } catch (Exception e) { throw new Exception("Error in base64Encode" + e.Message); } }
二:JS部分
//***************************************************************************************
// Autor:Tecky // Date:2008-06-03 // Desc:xxtea 算法的js加密处理类,还包含了UtfParser类,还包含了Base64类// e-mail:likui318@163.com // // var prefix = xt // // update: // // //***************************************************************************************function Xxtea(privateKey) {
this._keyString = privateKey; }//将长整形转换为string,private
Xxtea.prototype._long2str = function (v, w) { var vl = v.length; var n = (vl - 1) << 2; if (w) { var m = v[vl - 1]; if ((m < n - 3) || (m > n)) return null; n = m; } for (var i = 0; i < vl; i++) { v[i] = String.fromCharCode(v[i] & 0xff, v[i] >>> 8 & 0xff, v[i] >>> 16 & 0xff, v[i] >>> 24 & 0xff); } if (w) { return v.join('').substring(0, n); } else { return v.join(''); } }//将string转换为long,private
Xxtea.prototype._str2long = function (s, w) { var len = s.length; var v = []; for (var i = 0; i < len; i += 4) { v[i >> 2] = s.charCodeAt(i) | s.charCodeAt(i + 1) << 8 | s.charCodeAt(i + 2) << 16 | s.charCodeAt(i + 3) << 24; } if (w) { v[v.length] = len; } return v; }//function: encrypt str with private key by xxtea
Xxtea.prototype.xxtea_encrypt = function (str) { if (str == "") { return ""; } str = Base64.encode64(UtfParser.utf16to8(str)); var v = this._str2long(str, true); var k = this._str2long(this._keyString, false); if (k.length < 4) { k.length = 4; } var n = v.length - 1;var z = v[n], y = v[0], delta = 0x9E3779B9;
var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = 0; while (0 < q--) { sum = sum + delta & 0xffffffff; e = sum >>> 2 & 3; for (p = 0; p < n; p++) { y = v[p + 1]; mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); z = v[p] = v[p] + mx & 0xffffffff; } y = v[0]; mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); z = v[n] = v[n] + mx & 0xffffffff; }return Base64.encode64(this._long2str(v, false));
}//function: decrypt str with private key by xxtea
Xxtea.prototype.xxtea_decrypt = function (str) { if (str == "") { return ""; } str = Base64.decode64(str); var v = this._str2long(str, false); var k = this._str2long(this._keyString, false); if (k.length < 4) { k.length = 4; } var n = v.length - 1;var z = v[n - 1], y = v[0], delta = 0x9E3779B9;
var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = q * delta & 0xffffffff; while (sum != 0) { e = sum >>> 2 & 3; for (p = n; p > 0; p--) { z = v[p - 1]; mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); y = v[p] = v[p] - mx & 0xffffffff; } z = v[n]; mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); y = v[0] = v[0] - mx & 0xffffffff; sum = sum - delta & 0xffffffff; }return UtfParser.utf8to16(Base64.decode64(this._long2str(v, true)));
}//Class:utf16 to utf8, utf8 ot utf16
//Author:Tecky //Date:2008-06-03 function UtfParser() { //all method is static }//function:change utf16 to utf8
//parms(str):string that you want to change UtfParser.utf16to8 = function (str) { var out, i, len, c;out = "";
len = str.length; for (i = 0; i < len; i++) { c = str.charCodeAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { out += str.charAt(i); } else if (c > 0x07FF) { out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } else { out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } } return out; }//function:change utf8 to utf16
//parms(str):string that you want to change UtfParser.utf8to16 = function (str) { str = str.toString();var out, i, len, c;
var char2, char3;out = "";
len = str.length; i = 0; while (i < len) { c = str.charCodeAt(i++); switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx out += str.charAt(i - 1); break; case 12: case 13: // 110x xxxx 10xx xxxx char2 = str.charCodeAt(i++); out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: // 1110 xxxx 10xx xxxx 10xx xxxx char2 = str.charCodeAt(i++); char3 = str.charCodeAt(i++); out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break; } }return out;
}// Class:base64 encode & decode
// Autor:Tecky // Date:2008-06-03 function Base64() { //all method is static }//static
Base64._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; Base64.encode64 = function (input) { var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0;do {
chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++);enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63;if (isNaN(chr2)) {
enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; }output = output +
Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) + Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4); chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length);return output;
}Base64.decode64 = function (input) {
var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0;// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=\n]/g; if (base64test.exec(input)) { alert("There were invalid base64 characters in the input text.\n" + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" + "Expect errors in decoding."); } input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");do {
enc1 = Base64._keyStr.indexOf(input.charAt(i++)); enc2 = Base64._keyStr.indexOf(input.charAt(i++)); enc3 = Base64._keyStr.indexOf(input.charAt(i++)); enc4 = Base64._keyStr.indexOf(input.charAt(i++));chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4;output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); }chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";} while (i < input.length);
return output;
}