crypto.js
1 //import crypto from 'crypto' 2 3 function signed_crc_table() { 4 var c = 0, 5 table = new Array(256); 6 7 for (var n = 0; n != 256; ++n) { 8 c = n; 9 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 10 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 11 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 12 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 13 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 14 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 15 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 16 c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1)); 17 table[n] = c; 18 } 19 20 return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table; 21 } 22 23 var T = signed_crc_table(); 24 25 function crc32_str(str, seed) { 26 var C = seed ^ -1; 27 for (var i = 0, L = str.length, c, d; i < L;) { 28 c = str.charCodeAt(i++); 29 if (c < 0x80) { 30 C = (C >>> 8) ^ T[(C ^ c) & 0xFF]; 31 } else if (c < 0x800) { 32 C = (C >>> 8) ^ T[(C ^ (192 | ((c >> 6) & 31))) & 0xFF]; 33 C = (C >>> 8) ^ T[(C ^ (128 | (c & 63))) & 0xFF]; 34 } else if (c >= 0xD800 && c < 0xE000) { 35 c = (c & 1023) + 64; 36 d = str.charCodeAt(i++) & 1023; 37 C = (C >>> 8) ^ T[(C ^ (240 | ((c >> 8) & 7))) & 0xFF]; 38 C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 2) & 63))) & 0xFF]; 39 C = (C >>> 8) ^ T[(C ^ (128 | ((d >> 6) & 15) | ((c & 3) << 4))) & 0xFF]; 40 C = (C >>> 8) ^ T[(C ^ (128 | (d & 63))) & 0xFF]; 41 } else { 42 C = (C >>> 8) ^ T[(C ^ (224 | ((c >> 12) & 15))) & 0xFF]; 43 C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 6) & 63))) & 0xFF]; 44 C = (C >>> 8) ^ T[(C ^ (128 | (c & 63))) & 0xFF]; 45 } 46 } 47 return Math.abs(C ^ -1).toString(16); 48 } 49 50 // This async is really not necessary. 51 // There should be a better library 52 async function createHash(payload) { 53 const textBuffer = new TextEncoder().encode(payload) 54 const digest = await crypto.subtle.digest('SHA-256', textBuffer) 55 const hash = await digest 56 return hash 57 } 58 59 function buf2hex(buffer) { // buffer is an ArrayBuffer 60 return [...new Uint8Array(buffer)] 61 .map(x => x.toString(16).padStart(2, '0')) 62 .join(''); 63 } 64 65 function createCardHash(payload) { 66 let crchash = crc32_str(payload) 67 return crchash 68 } 69 70 async function hmacHex(message, secretKey, algorithm = "SHA-256") { 71 // Convert the message and secretKey to Uint8Array 72 const encoder = new TextEncoder(); 73 const messageUint8Array = encoder.encode(message); 74 const keyUint8Array = encoder.encode(secretKey); 75 76 // Import the secretKey as a CryptoKey 77 const cryptoKey = await crypto.subtle.importKey( 78 "raw", 79 keyUint8Array, 80 { name: "HMAC", hash: algorithm }, 81 false, 82 ["sign"] 83 ); 84 85 // Sign the message with HMAC and the CryptoKey 86 const signature = await crypto.subtle.sign( 87 "HMAC", 88 cryptoKey, 89 messageUint8Array 90 ); 91 92 // Convert the signature ArrayBuffer to a hex string 93 const hashArray = Array.from(new Uint8Array(signature)); 94 const hashHex = hashArray 95 .map((b) => b.toString(16).padStart(2, "0")) 96 .join(""); 97 98 return hashHex; 99 } 100 101 async function HMAC(key, message){ 102 const g = str => new Uint8Array([...unescape(encodeURIComponent(str))].map(c => c.charCodeAt(0))), 103 k = g(key), 104 m = g(message), 105 c = await crypto.subtle.importKey('raw', k, { name: 'HMAC', hash: 'SHA-256' },true, ['sign']), 106 s = await crypto.subtle.sign('HMAC', c, m); 107 return btoa(String.fromCharCode(...new Uint8Array(s))) 108 } 109 110 function derivePublicKey(p) { 111 return crypto.createPublicKey(p).export({ 112 type: 'spki', 113 format: 'pem' 114 }) 115 } 116 117 function encryptToPublic(pub, info) { 118 return crypto.publicEncrypt(pub, Buffer(info)).toString('hex') 119 } 120 121 function decryptFromPrivate(priv, hiddenInfo) { 122 return crypto.privateDecrypt(priv, Buffer.from(hiddenInfo, 'hex')).toString('latin1') 123 } 124 125 export default { 126 createCardHash, 127 createHash, 128 buf2hex, 129 hmacHex, 130 HMAC, 131 encryptToPublic, 132 decryptFromPrivate, 133 derivePublicKey 134 }