EncryptUtil.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. import { hmacSha256 } from "./encrypt/hmacSha256"
  2. import * as CryptoJS from "./encrypt/aes.js"
  3. /**
  4. * 加密解密工具类
  5. * @author 邹勇
  6. */
  7. export class EncryptUtil {
  8. /**
  9. * 随机生成多位字符串
  10. * @param len 字符串长度
  11. * @returns
  12. */
  13. public randomString(len = 32) {
  14. let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnoprstuvwxyz123456789';
  15. let maxPos = $chars.length;
  16. let pwd = '';
  17. for (let i = 0; i < len; i++) {
  18. pwd += $chars.charAt(Math.floor(Math.random() * maxPos))
  19. }
  20. return pwd;
  21. }
  22. //说明:
  23. // 1.如果加密解密涉及到前端和后端,则这里的key要保持和后端的key一致
  24. // 2.AES的算法模式有好几种(ECB,CBC,CFB,OFB),所以也要和后端保持一致
  25. // 3.AES的补码方式有两种(PKS5,PKS7),所以也要和后端保持一致
  26. // 4.AES的密钥长度有三种(128,192,256,默认是128),所以也要和后端保持一致
  27. // 5.AES的加密结果编码方式有两种(base64和十六进制),具体怎么选择由自己定,但是加密和解密的编码方式要统一
  28. //十六位十六进制数作为秘钥
  29. // private public key = fun_aes.CryptoJS.enc.Utf8.parse("3454345434543454");
  30. //十六位十六进制数作为秘钥偏移量
  31. // private public iv = fun_aes.CryptoJS.enc.Utf8.parse('6666666666666666');
  32. /**
  33. * 说明:
  34. * 1.如果加密解密涉及到前端和后端,则这里的key要保持和后端的key一致
  35. * 2.AES的算法模式有好几种(ECB,CBC,CFB,OFB),所以也要和后端保持一致
  36. * 3.AES的补码方式有两种(PKS5,PKS7),所以也要和后端保持一致
  37. * 4.AES的密钥长度有三种(128,192,256,默认是128),所以也要和后端保持一致
  38. * 5.AES的加密结果编码方式有两种(base64和十六进制),具体怎么选择由自己定,但是加密和解密的编码方式要统一
  39. * 十六位十六进制数作为秘钥
  40. * private public key = fun_aes.CryptoJS.enc.Utf8.parse("3454345434543454");
  41. * 十六位十六进制数作为秘钥偏移量
  42. * private public iv = fun_aes.CryptoJS.enc.Utf8.parse('6666666666666666');
  43. *
  44. * aes加密
  45. * @param word 需要加密的字符串
  46. * @param tkey !!!加密key,32位字符串,一般为sessionkey
  47. * @param appid 游戏的appid
  48. * @param state true 存包长 false /r/n
  49. * @returns
  50. */
  51. public encrypt(word, tkey, appid, state = true) {
  52. let tiv = tkey.substr(0, 16);
  53. //明文拼接
  54. let newStr = '';
  55. if (state) {
  56. newStr = tiv + word + appid;
  57. }
  58. else {
  59. newStr = tiv + word + '\r\n' + appid;
  60. }
  61. //加密后
  62. let key = CryptoJS.enc.Utf8.parse(tkey);
  63. let iv = CryptoJS.enc.Utf8.parse(tiv);
  64. newStr = CryptoJS.enc.Utf8.parse(newStr);
  65. let encrypted = CryptoJS.AES.encrypt(newStr, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
  66. encrypted = encrypted.toString();
  67. let mac = hmacSha256.Instance.hex_hmac_sha256(tkey, encrypted);
  68. return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(tiv + encrypted + mac));
  69. }
  70. /**
  71. * aes解密
  72. * @param word 需要加密的字符串
  73. * @param tkey 加密key,一般为sessionkey
  74. * @param appid 游戏的appid
  75. * @param state true 存包长 false /r/n
  76. * @returns
  77. */
  78. public decrypt(word, tkey, appid, state = true) {
  79. let en = CryptoJS.enc.Base64.parse(word).toString(CryptoJS.enc.Utf8);
  80. let newStrOne = en.substr(16);
  81. let temp = newStrOne.substr(0, newStrOne.length - 64);
  82. let de = temp;
  83. let key = CryptoJS.enc.Utf8.parse(tkey);
  84. let iv = CryptoJS.enc.Utf8.parse(tkey.substr(0, 16));
  85. let decrypt = CryptoJS.AES.decrypt(de, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
  86. let decryptedStr = CryptoJS.enc.Utf8.stringify(decrypt);
  87. decryptedStr = decryptedStr.toString();
  88. let newStrThree = '';
  89. if (state) {
  90. newStrThree = decryptedStr.slice(16).replace(new RegExp("(.*)" + appid), '$1');
  91. }
  92. else {
  93. newStrThree = decryptedStr.slice(16).split('\r\n')[0];
  94. }
  95. return newStrThree;
  96. }
  97. private options = {
  98. default_key_size: 2048,
  99. default_public_exponent: new Uint8Array([0x01, 0x00, 0x01])
  100. }
  101. /**
  102. * rsa加密
  103. * @param word 需要加密的字符串
  104. * @param isLong 字符串加长版
  105. * @returns
  106. */
  107. public rsaEncrypt(word, isLong: boolean = false) {
  108. let jsb = new window['JSEncrypt'](this.options);
  109. //公钥
  110. let publicString = '-----BEGIN PUBLIC KEY-----\n' +
  111. 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwz5V8wt525dMS+A9wOd\n' +
  112. 'NAjvKgxdyoXYuZSlAJEXLhvJlaXwFCKEsUg/qBBeo4nrRnwaFAjG7ItqbCWR9Ozv\n' +
  113. '6oY5tMYQnFFK82XkMGbKm1gG0z9vYKhcNYgHZHi+QKAw4tLLWXWO/QBTGelEXptD\n' +
  114. 'azlNmdM+8wHOknTcMuIyjc9Yo5qCoNsCJpA465vnREiBezBbKB3rSw+LmrRcZcFk\n' +
  115. 's8hmGtjpabcQ8sCxco7mRzVh6/DomNWfNm7hUP6shrrJirwjQtaS51grlScj8KhN\n' +
  116. 'h+kBoiI4Ad0Xz0GHasK5hAMf3sXDsN61r0An8KTfa/nsYSJDwogPIKkeKAsmw9Df\n' +
  117. 'EQIDAQAB\n' +
  118. '-----END PUBLIC KEY-----'
  119. jsb.setPublicKey(publicString);
  120. // 加密内容
  121. let encrypted = isLong ? jsb.encryptLong(word) : jsb.encrypt(word);
  122. return encrypted;
  123. }
  124. /**
  125. * for php pack( N , length )
  126. * @param len
  127. * @returns
  128. */
  129. public pack(len: number) {
  130. let buf: ArrayBuffer = new ArrayBuffer(4);
  131. let dataView = new DataView(buf);
  132. dataView.setUint32(0, len);
  133. let str2 = this.ab2str(buf);
  134. return str2;
  135. }
  136. /**
  137. *
  138. * @param array
  139. * @returns
  140. */
  141. public utf8ArrayToStr(array) {
  142. let out, i, len, c;
  143. let char2, char3;
  144. out = "";
  145. len = array.length;
  146. i = 0;
  147. while (i < len) {
  148. c = array[i++];
  149. switch (c >> 4) {
  150. case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
  151. // 0xxxxxxx
  152. out += String.fromCharCode(c);
  153. break;
  154. case 12: case 13:
  155. // 110x xxxx 10xx xxxx
  156. char2 = array[i++];
  157. out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
  158. break;
  159. case 14:
  160. // 1110 xxxx 10xx xxxx 10xx xxxx
  161. char2 = array[i++];
  162. char3 = array[i++];
  163. out += String.fromCharCode(((c & 0x0F) << 12) |
  164. ((char2 & 0x3F) << 6) |
  165. ((char3 & 0x3F) << 0));
  166. break;
  167. }
  168. }
  169. return out;
  170. }
  171. /**
  172. * UTF-16转UTF-8
  173. * @param s
  174. * @returns
  175. */
  176. public utf16ToUtf8(s) {
  177. if (!s) {
  178. return;
  179. }
  180. let i, code, ret = [], len = s.length;
  181. for (i = 0; i < len; i++) {
  182. code = s.charCodeAt(i);
  183. if (code > 0x0 && code <= 0x7f) {
  184. //单字节
  185. //UTF-16 0000 - 007F
  186. //UTF-8 0xxxxxxx
  187. ret.push(s.charAt(i));
  188. } else if (code >= 0x80 && code <= 0x7ff) {
  189. //双字节
  190. //UTF-16 0080 - 07FF
  191. //UTF-8 110xxxxx 10xxxxxx
  192. ret.push(
  193. //110xxxxx
  194. String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)),
  195. //10xxxxxx
  196. String.fromCharCode(0x80 | (code & 0x3f))
  197. );
  198. } else if (code >= 0x800 && code <= 0xffff) {
  199. //三字节
  200. //UTF-16 0800 - FFFF
  201. //UTF-8 1110xxxx 10xxxxxx 10xxxxxx
  202. ret.push(
  203. //1110xxxx
  204. String.fromCharCode(0xe0 | ((code >> 12) & 0xf)),
  205. //10xxxxxx
  206. String.fromCharCode(0x80 | ((code >> 6) & 0x3f)),
  207. //10xxxxxx
  208. String.fromCharCode(0x80 | (code & 0x3f))
  209. );
  210. }
  211. }
  212. return ret.join('');
  213. }
  214. /**
  215. * UTF-8转UTF-16
  216. * @param s
  217. * @returns
  218. */
  219. public utf8ToUtf16(s) {
  220. if (!s) {
  221. return;
  222. }
  223. let i, codes, bytes, ret = [], len = s.length;
  224. for (i = 0; i < len; i++) {
  225. codes = [];
  226. codes.push(s.charCodeAt(i));
  227. if (((codes[0] >> 7) & 0xff) == 0x0) {
  228. //单字节 0xxxxxxx
  229. ret.push(s.charAt(i));
  230. } else if (((codes[0] >> 5) & 0xff) == 0x6) {
  231. //双字节 110xxxxx 10xxxxxx
  232. codes.push(s.charCodeAt(++i));
  233. bytes = [];
  234. bytes.push(codes[0] & 0x1f);
  235. bytes.push(codes[1] & 0x3f);
  236. ret.push(String.fromCharCode((bytes[0] << 6) | bytes[1]));
  237. } else if (((codes[0] >> 4) & 0xff) == 0xe) {
  238. //三字节 1110xxxx 10xxxxxx 10xxxxxx
  239. codes.push(s.charCodeAt(++i));
  240. codes.push(s.charCodeAt(++i));
  241. bytes = [];
  242. bytes.push((codes[0] << 4) | ((codes[1] >> 2) & 0xf));
  243. bytes.push(((codes[1] & 0x3) << 6) | (codes[2] & 0x3f));
  244. ret.push(String.fromCharCode((bytes[0] << 8) | bytes[1]));
  245. }
  246. }
  247. return ret.join('');
  248. }
  249. /**
  250. * ArrayBuffer转为字符串,参数为ArrayBuffer对象
  251. * @param buf
  252. * @returns
  253. */
  254. public ab2str(buf: ArrayBuffer) {
  255. return String.fromCharCode.apply(null, new Uint8Array(buf));
  256. }
  257. /**
  258. *
  259. * @param fileData
  260. * @returns
  261. */
  262. public uint8ArrayToString(fileData) {
  263. let dataString = "";
  264. for (let i = 0; i < fileData.length; i++) {
  265. dataString += String.fromCharCode(fileData[i]);
  266. }
  267. return dataString
  268. }
  269. /**
  270. *
  271. * @param str
  272. * @returns
  273. */
  274. public stringToUint8Array(str) {
  275. let arr = [];
  276. for (let i = 0, j = str.length; i < j; ++i) {
  277. arr.push(str.charCodeAt(i));
  278. }
  279. let tmpUint8Array = new Uint8Array(arr);
  280. return tmpUint8Array
  281. }
  282. /**
  283. * 字符串转为ArrayBuffer对象,参数为字符串
  284. * @param str
  285. * @returns
  286. */
  287. public str2ab(str) {
  288. let buf = new ArrayBuffer(str.length); // 每个字符占用2个字节
  289. let bufView = new Uint8Array(buf);
  290. for (let i = 0, strLen = str.length; i < strLen; i++) {
  291. bufView[i] = str.charCodeAt(i);
  292. }
  293. return buf;
  294. }
  295. }