crypto.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /**
  2. * @created by helin3 2018-10-29
  3. * @updated by
  4. * @description 加密实现工具方法,后续有新增实现,请增加加密算法-将rollups目录下内容复制到本文件末尾的TODO imports区域追加,该工具支持加密算法有:
  5. * aes,hmac-md5,hmac-ripemd160,hmac-sha1,hmac-sha224,hmac-sha256,hmac-sha3,hmac-sha384,hmac-sha512,md5,pbkdf2,rabbit,rabbit-legacy,rc4,ripemd160,sha1,sha224,sha256,sha3,sha384,sha512,tripledes,
  6. */
  7. /**
  8. crypto-js/core
  9. crypto-js/x64-core
  10. crypto-js/lib-typedarrays
  11. crypto-js/md5
  12. crypto-js/sha1
  13. crypto-js/sha256
  14. crypto-js/sha224
  15. crypto-js/sha512
  16. crypto-js/sha384
  17. crypto-js/sha3
  18. crypto-js/ripemd160
  19. crypto-js/hmac-md5
  20. crypto-js/hmac-sha1
  21. crypto-js/hmac-sha256
  22. crypto-js/hmac-sha224
  23. crypto-js/hmac-sha512
  24. crypto-js/hmac-sha384
  25. crypto-js/hmac-sha3
  26. crypto-js/hmac-ripemd160
  27. crypto-js/pbkdf2
  28. crypto-js/aes
  29. crypto-js/tripledes
  30. crypto-js/rc4
  31. crypto-js/rabbit
  32. crypto-js/rabbit-legacy
  33. crypto-js/evpkdf
  34. crypto-js/format-openssl
  35. crypto-js/format-hex
  36. crypto-js/enc-latin1
  37. crypto-js/enc-utf8
  38. crypto-js/enc-hex
  39. crypto-js/enc-utf16
  40. crypto-js/enc-base64
  41. crypto-js/mode-cfb
  42. crypto-js/mode-ctr
  43. crypto-js/mode-ctr-gladman
  44. crypto-js/mode-ofb
  45. crypto-js/mode-ecb
  46. crypto-js/pad-pkcs7
  47. crypto-js/pad-ansix923
  48. crypto-js/pad-iso10126
  49. crypto-js/pad-iso97971
  50. crypto-js/pad-zeropadding
  51. crypto-js/pad-nopadding
  52. */
  53. import logger from './logger';
  54. import request from './request';
  55. import hmacSHA256 from 'crypto-js/hmac-sha256';
  56. import hmacSHA512 from 'crypto-js/hmac-sha512';
  57. import AES from 'crypto-js/aes';
  58. import Pkcs7 from 'crypto-js/pad-pkcs7';
  59. import Utf8 from 'crypto-js/enc-utf8';
  60. import Base64 from 'crypto-js/enc-base64';
  61. import ECB from 'crypto-js/mode-ecb';
  62. import { mode } from 'crypto-js';
  63. import TripleDES from 'crypto-js/tripledes';
  64. import { sessionStore } from './storage';
  65. const backend = {
  66. uaaService: ''
  67. };
  68. /**
  69. * 报文安全处理
  70. */
  71. function Crypto () {
  72. this.initialCfg = {
  73. storeKey: 'UFP-ENCRYPT-KEY', // 存储密钥KEY
  74. hmac: 'SHA256', // 采用哪种hmac算法:SHA256、SHA512
  75. AESkey: '', // 十六位十六进制数作为密钥
  76. AESAESiv: '', // 十六位十六进制数作为密钥偏移量
  77. hmacKey: null, // hmac默认密钥
  78. hmacUrl: backend.uaaService + '/ua/n/secretkey/exchange', // 握手确认签名密钥,即握手生成上述hmacKey
  79. rsaPubKey: null, // rsa默认公钥
  80. rsaPrivKey: null // rsa默认私钥
  81. };
  82. };
  83. /**
  84. * 设置测试RSA公私钥,真正使用时,考虑性能优化时,可删除此方法
  85. */
  86. Crypto.prototype.setTestRsaKey = function () {
  87. var rsaPubKey = '-----BEGIN PUBLIC KEY-----' +
  88. 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN' +
  89. 'FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76' +
  90. 'xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4' +
  91. 'gwQco1KRMDSmXSMkDwIDAQAB' +
  92. '-----END PUBLIC KEY-----';
  93. var rsaPrivKey = '-----BEGIN RSA PRIVATE KEY-----' +
  94. 'MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQ' +
  95. 'WMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNR' +
  96. 'aY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB' +
  97. 'AoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fv' +
  98. 'xTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeH' +
  99. 'm7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd' +
  100. '8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAF' +
  101. 'z/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5' +
  102. 'rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIM' +
  103. 'V7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATe' +
  104. 'aTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5Azil' +
  105. 'psLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Oz' +
  106. 'uku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876' +
  107. '-----END RSA PRIVATE KEY-----';
  108. this.setRsaPubKey(rsaPubKey);
  109. this.setRsaPrivKey(rsaPrivKey);
  110. };
  111. /**
  112. * 存储相关密钥
  113. */
  114. Crypto.prototype.storeEncryptKey = function () {
  115. sessionStore.put(this.initialCfg.storeKey, JSON.stringify(this.initialCfg));
  116. };
  117. /**
  118. * 移除相关密钥
  119. */
  120. Crypto.prototype.removeEncryptKey = function () {
  121. sessionStore.remove(this.initialCfg.storeKey);
  122. };
  123. /**
  124. * 刷新时获取/初始化相关密钥
  125. */
  126. Crypto.prototype.readEncryptKey = function () {
  127. var storeKey = sessionStore.get(this.initialCfg.storeKey);
  128. if (storeKey) {
  129. this.initialCfg = JSON.parse(storeKey);
  130. }
  131. return storeKey;
  132. };
  133. /**
  134. * hmac默认密钥
  135. * @param {string} hmacKey 密钥
  136. */
  137. Crypto.prototype.setHmacKey = function (hmacKey) {
  138. this.initialCfg.hmacKey = hmacKey;
  139. };
  140. /**
  141. * 设置RSA公钥
  142. * @param {string} rsaPubKey 公钥
  143. */
  144. Crypto.prototype.setRsaPubKey = function (rsaPubKey) {
  145. this.initialCfg.rsaPubKey = rsaPubKey;
  146. };
  147. /**
  148. * 设置RSA私钥
  149. * @param {string} rsaPrivKey 私钥
  150. */
  151. Crypto.prototype.setRsaPrivKey = function (rsaPrivKey) {
  152. this.initialCfg.rsaPrivKey = rsaPrivKey;
  153. };
  154. /**
  155. * 密钥相关的哈希运算加密,目前默认使用HMAC-SHA256
  156. * @param {string} message 报文体
  157. * @param {string} hmacKey 密钥
  158. */
  159. Crypto.prototype.hmacEncrypt = function (message, hmacKey) {
  160. var encrypted;
  161. if (this.initialCfg.hmac === 'SHA256') {
  162. encrypted = this.hmacSha256(message, hmacKey);
  163. } else if (this.initialCfg.hmac === 'SHA512') {
  164. encrypted = this.hmacSha512(message, hmacKey);
  165. }
  166. return encrypted;
  167. };
  168. /**
  169. * HMAC-SHA256 加密哈希
  170. * @param {string} message 报文体
  171. * @param {string} hmacKey 密钥
  172. */
  173. Crypto.prototype.hmacSha256 = function (message, hmacKey) {
  174. var hmac;
  175. try {
  176. hmacKey = hmacKey || this.initialCfg.hmacKey;
  177. hmac = Base64.stringify(hmacSHA256(message, hmacKey));
  178. } catch (e) {
  179. logger.error('Crypto: hmac compute error! ', e);
  180. }
  181. return hmac;
  182. };
  183. /**
  184. * HMAC-SHA512 加密哈希
  185. * @param {string} message 报文体
  186. * @param {string} hmacKey 密钥
  187. */
  188. Crypto.prototype.hmacSha512 = function (message, hmacKey) {
  189. var hmac;
  190. try {
  191. hmacKey = hmacKey || this.initialCfg.hmacKey;
  192. hmac = Base64.stringify(hmacSHA512(message, hmacKey));
  193. } catch (e) {
  194. logger.error('Crypto: hmac compute error! ', e);
  195. }
  196. return hmac;
  197. };
  198. /**
  199. * rsa 公钥加密
  200. * @param {string} message 加密报文体
  201. * @param {string} rsaPubKey 公钥,可选项
  202. */
  203. Crypto.prototype.rsaEncrypt = function (message, rsaPubKey) {
  204. var text;
  205. try {
  206. rsaPubKey = rsaPubKey || this.initialCfg.rsaPubKey;
  207. const jsencrypt = new window.JSEncrypt();
  208. jsencrypt.setPublicKey(rsaPubKey);
  209. text = jsencrypt.encrypt(message);
  210. } catch (e) {
  211. logger.error('Crypto: rsa encrypt compute error! ', e);
  212. }
  213. return text;
  214. };
  215. /**
  216. * rsa 私钥解密
  217. * @param {string} message 解密报文
  218. * @param {string} rsaPrivKey 私钥,可选项
  219. */
  220. Crypto.prototype.rsaDecrypt = function (message, rsaPrivKey) {
  221. try {
  222. rsaPrivKey = rsaPrivKey || this.initialCfg.rsaPrivKey;
  223. const jsencrypt = new window.JSEncrypt();
  224. jsencrypt.setPrivateKey(rsaPrivKey);
  225. return jsencrypt.decrypt(message);
  226. } catch (e) {
  227. logger.error('Crypto: rsa decrypt compute error! ', e);
  228. }
  229. return undefined;
  230. };
  231. Crypto.prototype.aesInit = function () {
  232. this.initialCfg.AESkey = 'aaaabbbbccccddddeeeeffffgggghhhh'; // 十六位十六进制数作为密钥
  233. this.initialCfg.AESAESiv = '1234567812345678'; // 十六位十六进制数作为密钥偏移量
  234. // console.log('kongqf', this.aesEncrypt('kongqf'), this.aesDecrypt(this.aesEncrypt('kongqf')));
  235. };
  236. /**
  237. * AES解密
  238. * @param {String} word 待解密字符串
  239. */
  240. Crypto.prototype.aesDecrypt = function (word) {
  241. return AES.decrypt(word, Utf8.parse(this.initialCfg.AESkey), {
  242. iv: Utf8.parse(this.initialCfg.AESAESiv),
  243. mode: mode.CBC,
  244. padding: Pkcs7
  245. }).toString(Utf8);
  246. };
  247. /**
  248. * 加密方法,取值时,需要使用toString()转换成字符串
  249. * @param {String} word 待加密字符串
  250. */
  251. Crypto.prototype.aesEncrypt = function (word) {
  252. return AES.encrypt(word, Utf8.parse(this.initialCfg.AESkey), {
  253. iv: Utf8.parse(this.initialCfg.AESAESiv),
  254. mode: mode.CBC,
  255. padding: Pkcs7
  256. }).toString();
  257. };
  258. /**
  259. * 握手确认交易请求密钥
  260. * @param {string} tokenId 公钥
  261. * @param {string} rsaPubKey 公钥
  262. * @param {function} callback 回调方法
  263. */
  264. Crypto.prototype.sign = function (tokenId, rsaPubKey, callback) {
  265. // 设置保存客户端TokenId
  266. // zyfp.service.putToken(tokenId);
  267. // 设置保存客户端公钥
  268. this.setRsaPubKey(rsaPubKey);
  269. const hmacKeyA = this.uuid();
  270. request({
  271. needHmac: false,
  272. url: this.initialCfg.hmacUrl,
  273. method: 'post',
  274. data: {
  275. tokenId: tokenId,
  276. clientSecretKey: this.rsaEncrypt(hmacKeyA)
  277. }
  278. }).then(res => {
  279. const { data } = res;
  280. var serverSecretKey = data.serverSecretKey || '';
  281. if (serverSecretKey) {
  282. const hmacKeyB = this.tripleDesDecrypt(serverSecretKey, hmacKeyA);
  283. this.setHmacKey(hmacKeyA + hmacKeyB);
  284. this.storeEncryptKey();
  285. if (typeof callback === 'function') {
  286. callback();
  287. }
  288. } else {
  289. logger.error('密钥接口返回数据异常');
  290. }
  291. });
  292. };
  293. /**
  294. * 3des加密
  295. * @param {string} message 明文
  296. * @param {string} desKey 密钥
  297. */
  298. Crypto.prototype.tripleDesEncrypt = function (message, desKey) {
  299. try {
  300. const keyHex = Utf8.parse(desKey);
  301. return TripleDES.encrypt(message, keyHex, {
  302. mode: ECB,
  303. padding: Pkcs7
  304. }).toString();
  305. } catch (e) {
  306. logger.error('Crypto: 3des encrypt compute error! ', e);
  307. }
  308. return undefined;
  309. };
  310. /**
  311. * 3des解密
  312. * @param {string} ciphertext 密文
  313. * @param {string} desKey 密钥
  314. */
  315. Crypto.prototype.tripleDesDecrypt = function (ciphertext, desKey) {
  316. try {
  317. const keyHex = Utf8.parse(desKey);
  318. return TripleDES.decrypt({
  319. ciphertext: Base64.parse(ciphertext)
  320. }, keyHex, {
  321. mode: ECB,
  322. padding: Pkcs7
  323. }).toString(Utf8);
  324. } catch (e) {
  325. logger.error('Crypto: 3des decrypt compute error! ', e);
  326. }
  327. return undefined;
  328. };
  329. // 随机数UUID生成器集成
  330. const hexBytes = [];
  331. // Cache toString(16)
  332. // This is massively impactful on performance
  333. for (let i = 0; i < 256; i++) {
  334. // This is a fast way to ensure a 2 char hex byte
  335. hexBytes[i] = (i + 0x100).toString(16).substr(1);
  336. }
  337. const getRandomInt = function (min, max) {
  338. return Math.floor(Math.random() * (max - min)) + min;
  339. };
  340. const uuidbin = function () {
  341. const b = [];
  342. for (let i = 0; i < 16; i++) {
  343. b.push(getRandomInt(0, 255));
  344. };
  345. b[6] = (b[6] & 0x0f) | 0x40;
  346. b[8] = (b[8] & 0x3f) | 0x80;
  347. return b;
  348. };
  349. /**
  350. * 随机数32位UUID
  351. */
  352. Crypto.prototype.uuid = function () {
  353. var b = uuidbin();
  354. return hexBytes[b[0]] + hexBytes[b[1]] +
  355. hexBytes[b[2]] + hexBytes[b[3]] + // '-' +
  356. hexBytes[b[4]] + hexBytes[b[5]] + // '-' +
  357. hexBytes[b[6]] + hexBytes[b[7]] + // '-' +
  358. hexBytes[b[8]] + hexBytes[b[9]] + // '-' +
  359. hexBytes[b[10]] + hexBytes[b[11]] +
  360. hexBytes[b[12]] + hexBytes[b[13]] +
  361. hexBytes[b[14]] + hexBytes[b[15]];
  362. };
  363. export default new Crypto();