tea javascript算法,支持utf8编码,解码方案。


  1. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  2. /* Block TEA (xxtea) Tiny Encryption Algorithm implementation in JavaScript */
  3. /* (c) Chris Veness 2002-2009: www.movable-type.co.uk/tea-block.html */
  4. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  5. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  6. /* Algorithm: David Wheeler & Roger Needham, Cambridge University Computer Lab */
  7. /* http://www.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html (1994) */
  8. /* http://www.cl.cam.ac.uk/ftp/users/djw3/xtea.ps (1997) */
  9. /* http://www.cl.cam.ac.uk/ftp/users/djw3/xxtea.ps (1998) */
  10. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  11.  
  12. var Tea = {}; // Tea namespace
  13.  
  14. /*
  15. * encrypt text using Corrected Block TEA (xxtea) algorithm
  16. *
  17. <span id="more-119"></span>
  18. * @param {string} plaintext String to be encrypted (multi-byte safe)
  19. * @param {string} password Password to be used for encryption (1st 16 chars)
  20. * @returns {string} encrypted text
  21. */
  22. Tea.encrypt = function(plaintext, password) {
  23. if (plaintext.length == 0) return(”); // nothing to encrypt
  24.  
  25. // convert string to array of longs after converting any multi-byte chars to UTF-8
  26. var v = Tea.strToLongs(Utf8.encode(plaintext));
  27. if (v.length <= 1) v[1] = 0; // algorithm doesn’t work for n<2 so fudge by adding a null
  28. // simply convert first 16 chars of password as key
  29. var k = Tea.strToLongs(Utf8.encode(password).slice(0,16));
  30. var n = v.length;
  31.  
  32. // —- —-
  33.  
  34. var z = v[n-1], y = v[0], delta = 0x9E3779B9;
  35. var mx, e, q = Math.floor(6 + 52/n), sum = 0;
  36.  
  37. while (q– > 0) { // 6 + 52/n operations gives between 6 &amp; 32 mixes on each word
  38. sum += delta;
  39. e = sum>>>2 &amp; 3;
  40. for (var p = 0; p < n; p++) {
  41. y = v[(p+1)%n];
  42. mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&amp;3 ^ e] ^ z);
  43. z = v[p] += mx;
  44. }
  45. }
  46.  
  47. // —- —-
  48.  
  49. var ciphertext = Tea.longsToStr(v);
  50.  
  51. return Base64.encode(ciphertext);
  52. }
  53.  
  54. /*
  55. * decrypt text using Corrected Block TEA (xxtea) algorithm
  56. *
  57. * @param {string} ciphertext String to be decrypted
  58. * @param {string} password Password to be used for decryption (1st 16 chars)
  59. * @returns {string} decrypted text
  60. */
  61. Tea.decrypt = function(ciphertext, password) {
  62. if (ciphertext.length == 0) return(”);
  63. var v = Tea.strToLongs(Base64.decode(ciphertext));
  64. var k = Tea.strToLongs(Utf8.encode(password).slice(0,16));
  65. var n = v.length;
  66.  
  67. // —- —-
  68.  
  69. var z = v[n-1], y = v[0], delta = 0x9E3779B9;
  70. var mx, e, q = Math.floor(6 + 52/n), sum = q*delta;
  71.  
  72. while (sum != 0) {
  73. e = sum>>>2 &amp; 3;
  74. for (var p = n-1; p >= 0; p–) {
  75. z = v[p>0 ? p-1 : n-1];
  76. mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&amp;3 ^ e] ^ z);
  77. y = v[p] -= mx;
  78. }
  79. sum -= delta;
  80. }
  81.  
  82. // —- —-
  83.  
  84. var plaintext = Tea.longsToStr(v);
  85.  
  86. // strip trailing null chars resulting from filling 4-char blocks:
  87. plaintext = plaintext.replace(/\0+$/,”);
  88.  
  89. return Utf8.decode(plaintext);
  90. }
  91.  
  92. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  93.  
  94. // supporting functions
  95.  
  96. Tea.strToLongs = function(s) { // convert string to array of longs, each containing 4 chars
  97. // note chars must be within ISO-8859-1 (with Unicode code-point < 256) to fit 4/long
  98. var l = new Array(Math.ceil(s.length/4));
  99. for (var i=0; i // note little-endian encoding – endianness is irrelevant as long as
  100. // it is the same in longsToStr()
  101. l[i] = s.charCodeAt(i*4) + (s.charCodeAt(i*4+1)<<8) +
  102. (s.charCodeAt(i*4+2)<<16) + (s.charCodeAt(i*4+3)<<24);
  103. }
  104. return l; // note running off the end of the string generates nulls since
  105. } // bitwise operators treat NaN as 0
  106.  
  107. Tea.longsToStr = function(l) { // convert array of longs back to string
  108. var a = new Array(l.length);
  109. for (var i=0; i a[i] = String.fromCharCode(l[i] &amp; 0xFF, l[i]>>>8 &amp; 0xFF,
  110. l[i]>>>16 &amp; 0xFF, l[i]>>>24 &amp; 0xFF);
  111. }
  112. return a.join(”); // use Array.join() rather than repeated string appends for efficiency in IE
  113. }
  114.  
  115. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  116. /* Base64 class: Base 64 encoding / decoding (c) Chris Veness 2002-2009 */
  117. /* note: depends on Utf8 class */
  118. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  119.  
  120. var Base64 = {}; // Base64 namespace
  121.  
  122. Base64.code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  123.  
  124. /**
  125. * Encode string into Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
  126. * (instance method extending String object). As per RFC 4648, no newlines are added.
  127. *
  128. * @param {String} str The string to be encoded as base-64
  129. * @param {Boolean} [utf8encode=false] Flag to indicate whether str is Unicode string to be encoded
  130. * to UTF8 before conversion to base64; otherwise string is assumed to be 8-bit characters
  131. * @returns {String} Base64-encoded string
  132. */
  133. Base64.encode = function(str, utf8encode) { // http://tools.ietf.org/html/rfc4648
  134. utf8encode = (typeof utf8encode == ‘undefined’) ? false : utf8encode;
  135. var o1, o2, o3, bits, h1, h2, h3, h4, e=[], pad = ”, c, plain, coded;
  136. var b64 = Base64.code;
  137.  
  138. plain = utf8encode ? str.encodeUTF8() : str;
  139.  
  140. c = plain.length % 3; // pad string to length of multiple of 3
  141. if (c > 0) { while (c++ < 3) { pad += ‘=’; plain += ‘\0′; } }
  142. // note: doing padding here saves us doing special-case packing for trailing 1 or 2 chars
  143.  
  144. for (c=0; c o1 = plain.charCodeAt(c);
  145. o2 = plain.charCodeAt(c+1);
  146. o3 = plain.charCodeAt(c+2);
  147.  
  148. bits = o1<<16 | o2<<8 | o3;
  149.  
  150. h1 = bits>>18 &amp; 0x3f;
  151. h2 = bits>>12 &amp; 0x3f;
  152. h3 = bits>>6 &amp; 0x3f;
  153. h4 = bits &amp; 0x3f;
  154.  
  155. // use hextets to index into code string
  156. e[c/3] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  157. }
  158. coded = e.join(”); // join() is far faster than repeated string concatenation in IE
  159.  
  160. // replace ‘A’s from padded nulls with ‘=’s
  161. coded = coded.slice(0, coded.length-pad.length) + pad;
  162.  
  163. return coded;
  164. }
  165.  
  166. /**
  167. * Decode string from Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
  168. * (instance method extending String object). As per RFC 4648, newlines are not catered for.
  169. *
  170. * @param {String} str The string to be decoded from base-64
  171. * @param {Boolean} [utf8decode=false] Flag to indicate whether str is Unicode string to be decoded
  172. * from UTF8 after conversion from base64
  173. * @returns {String} decoded string
  174. */
  175. Base64.decode = function(str, utf8decode) {
  176. utf8decode = (typeof utf8decode == ‘undefined’) ? false : utf8decode;
  177. var o1, o2, o3, h1, h2, h3, h4, bits, d=[], plain, coded;
  178. var b64 = Base64.code;
  179.  
  180. coded = utf8decode ? str.decodeUTF8() : str;
  181.  
  182. for (var c=0; c h1 = b64.indexOf(coded.charAt(c));
  183. h2 = b64.indexOf(coded.charAt(c+1));
  184. h3 = b64.indexOf(coded.charAt(c+2));
  185. h4 = b64.indexOf(coded.charAt(c+3));
  186.  
  187. bits = h1<<18 | h2<<12 | h3<<6 | h4;
  188.  
  189. o1 = bits>>>16 &amp; 0xff;
  190. o2 = bits>>>8 &amp; 0xff;
  191. o3 = bits &amp; 0xff;
  192.  
  193. d[c/4] = String.fromCharCode(o1, o2, o3);
  194. // check for padding
  195. if (h4 == 0×40) d[c/4] = String.fromCharCode(o1, o2);
  196. if (h3 == 0×40) d[c/4] = String.fromCharCode(o1);
  197. }
  198. plain = d.join(”); // join() is far faster than repeated string concatenation in IE
  199.  
  200. return utf8decode ? plain.decodeUTF8() : plain;
  201. }
  202.  
  203. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  204. /* Utf8 class: encode / decode between multi-byte Unicode characters and UTF-8 multiple */
  205. /* single-byte character encoding (c) Chris Veness 2002-2009 */
  206. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  207.  
  208. var Utf8 = {}; // Utf8 namespace
  209.  
  210. /**
  211. * Encode multi-byte Unicode string into utf-8 multiple single-byte characters
  212. * (BMP / basic multilingual plane only)
  213. *
  214. * Chars in range U+0080 – U+07FF are encoded in 2 chars, U+0800 – U+FFFF in 3 chars
  215. *
  216. * @param {String} strUni Unicode string to be encoded as UTF-8
  217. * @returns {String} encoded string
  218. */
  219. Utf8.encode = function(strUni) {
  220. // use regular expressions &amp; String.replace callback function for better efficiency
  221. // than procedural approaches
  222. var strUtf = strUni.replace(
  223. /[\u0080-\u07ff]/g, // U+0080 – U+07FF => 2 bytes 110yyyyy, 10zzzzzz
  224. function(c) {
  225. var cc = c.charCodeAt(0);
  226. return String.fromCharCode(0xc0 | cc>>6, 0×80 | cc&amp;0x3f); }
  227. );
  228. strUtf = strUtf.replace(
  229. /[\u0800-\uffff]/g, // U+0800 – U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
  230. function(c) {
  231. var cc = c.charCodeAt(0);
  232. return String.fromCharCode(0xe0 | cc>>12, 0×80 | cc>>6&amp;0x3F, 0×80 | cc&amp;0x3f); }
  233. );
  234. return strUtf;
  235. }
  236.  
  237. /**
  238. * Decode utf-8 encoded string back into multi-byte Unicode characters
  239. *
  240. * @param {String} strUtf UTF-8 string to be decoded back to Unicode
  241. * @returns {String} decoded string
  242. */
  243. Utf8.decode = function(strUtf) {
  244. var strUni = strUtf.replace(
  245. /[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
  246. function(c) { // (note parentheses for precence)
  247. var cc = (c.charCodeAt(0)&amp;0x1f)<<6 | c.charCodeAt(1)&amp;0x3f;
  248. return String.fromCharCode(cc); }
  249. );
  250. strUni = strUni.replace(
  251. /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
  252. function(c) { // (note parentheses for precence)
  253. var cc = ((c.charCodeAt(0)&amp;0x0f)<<12) | ((c.charCodeAt(1)&amp;0x3f)<<6) | ( c.charCodeAt(2)&amp;0x3f);
  254. return String.fromCharCode(cc); }
  255. );
  256. return strUni;
  257. }
  258.  
  259. /* – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – */
  260.  
  261. 普通的tea算法的
  262. // use (16 chars of) ‘password’ to encrypt ‘plaintext’
  263.  
  264. function encrypt(plaintext, password) {
  265.   var v = new Array(2), k = new Array(4), s = "", i;
  266.  
  267.   plaintext = escape(plaintext);  // use escape() so only have single-byte chars to encode
  268.  
  269.   // build key directly from 1st 16 chars of password
  270.   for (var i=0; i<4; i++) k[i] = Str4ToLong(password.slice(i*4,(i+1)*4));
  271.  
  272.   for (i=0; i
  273.     v[0] = Str4ToLong(plaintext.slice(i,i+4));  // … note this is ‘electronic codebook’ mode
  274.     v[1] = Str4ToLong(plaintext.slice(i+4,i+8));
  275.     code(v, k);
  276.     s += LongToStr4(v[0]) + LongToStr4(v[1]);
  277.   }
  278.  
  279.   return escCtrlCh(s);
  280.   // note: if plaintext or password are passed as string objects, rather than strings, this
  281.   // function will throw an ‘Object doesn’t support this property or method’ error
  282. }
  283.  
  284. // use (16 chars of) ‘password’ to decrypt ‘ciphertext’ with xTEA
  285.  
  286. function decrypt(ciphertext, password) {
  287.   var v = new Array(2), k = new Array(4), s = "", i;
  288.  
  289.   for (var i=0; i<4; i++) k[i] = Str4ToLong(password.slice(i*4,(i+1)*4));
  290.  
  291.   ciphertext = unescCtrlCh(ciphertext);
  292.   for (i=0; i
  293.     v[0] = Str4ToLong(ciphertext.slice(i,i+4));
  294.     v[1] = Str4ToLong(ciphertext.slice(i+4,i+8));
  295.     decode(v, k);
  296.     s += LongToStr4(v[0]) + LongToStr4(v[1]);
  297.   }
  298.  
  299.   // strip trailing null chars resulting from filling 4-char blocks:
  300.   s = s.replace(/\0+$/, ”);
  301.  
  302.   return unescape(s);
  303. }
  304.  
  305. function code(v, k) {
  306.   // Extended TEA: this is the 1997 revised version of Needham &amp; Wheeler’s algorithm
  307.   // params: v[2] 64-bit value block; k[4] 128-bit key
  308.   var y = v[0], z = v[1];
  309.   var delta = 0x9E3779B9, limit = delta*32, sum = 0;
  310.  
  311.   while (sum != limit) {
  312.     y += (z<<4 ^ z>>>5)+z ^ sum+k[sum &amp; 3];
  313.     sum += delta;
  314.     z += (y<<4 ^ y>>>5)+y ^ sum+k[sum>>>11 &amp; 3];
  315.     // note: unsigned right-shift ‘>>>’ is used in place of original ‘>>’, due to lack
  316.     // of ‘unsigned’ type declaration in JavaScript (thanks to Karsten Kraus for this)
  317.   }
  318.   v[0] = y; v[1] = z;
  319. }
  320.  
  321. function decode(v, k) {
  322.   var y = v[0], z = v[1];
  323.   var delta = 0x9E3779B9, sum = delta*32;
  324.  
  325.   while (sum != 0) {
  326.     z -= (y<<4 ^ y>>>5)+y ^ sum+k[sum>>>11 &amp; 3];
  327.     sum -= delta;
  328.     y -= (z<<4 ^ z>>>5)+z ^ sum+k[sum &amp; 3];
  329.   }
  330.   v[0] = y; v[1] = z;
  331. }
  332.  
  333. // supporting functions
  334.  
  335. function Str4ToLong(s) {  // convert 4 chars of s to a numeric long
  336.   var v = 0;
  337.   for (var i=0; i<4; i++) v |= s.charCodeAt(i) << i*8;   return isNaN(v) ? 0 : v; } function LongToStr4(v) {  // convert a numeric long to 4 char string   var s = String.fromCharCode(v &amp; 0xFF, v>>8 &amp; 0xFF, v>>16 &amp; 0xFF, v>>24 &amp; 0xFF);
  338.   return s;
  339. }
  340.  
  341. function escCtrlCh(str) {  // escape control chars which might cause problems with encrypted texts
  342.   return str.replace(/[\0\t\n\v\f\r\xa0'"!]/g, function(c) { return ‘!’ + c.charCodeAt(0) + ‘!’; });
  343. }
  344.  
  345. function unescCtrlCh(str) {  // unescape potentially problematic nulls and control characters
  346.   return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
  347. }
  348.  
  1. No comments yet.
(will not be published)
  1. No trackbacks yet.