const fs = require("fs"); const path = require("path"); const { parse } = require("querystring"); const { createVerify, createPrivateKey } = require("crypto"); const NodeRSA = require('node-rsa'); const base64 = require('base-64'); const PRIVATE_KEY =`-----BEGIN RSA PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK/q2uuuf+s4pd2gkVAyhHkpog1o4RL5+Dm2ZOe5i7O/ELKJvj/9JIrNO1abNNuG8g2nvBnOeJ5uii1q83Qy9C4aaey1UjqYd3iVupuO8Xfmr/3sHTec6R8X0HZnuQ/fsU8uREYEQFUfBFcZtiNz2TqXfjJXMXAeTpXc6CbKOLe3AgMBAAECgYAYDVvWSnsJ7apb9Ya4uNd8+3DBNZxEbHIAbgw41Jkhv9doGcYt2I4k/i+FRV5CP56buFnTC3RZcRKqaAuWURsqcnDG8ufFIhoSEiD11FcFrXanFdixfj9gijuPiTE4w9f07eDVEfdQjFMSO8tYDbsMUoaMPUTOoreqyy86uW0G0QJBAN5zaUsxjgtJhqO3OsoHXpu+67bsM2ounuoHWq7KehiVeb9ykrS6quZ1+r5+0SIMEFkKZKbpwfIG+Hi9NII85/ECQQDKctaP1WQzuLQvm97lfQEfgY/JWL9RZuWriGd7fDT7Nrl0FTK5O9q22HvJdwIQktaTOQca28KzHucIxa7ouYInAkB1KehteF5OR52ooRtPyW3lLjvMjr/Nz1xX+yOiKHcCd8g2M8xdcGwPEljM+NKB0kTSAQ1edIR4S3+XaGA9sIKhAkEAsfVaqJry9wgw0/zXZbGJsDFKvLpXiu3BjBReqszXIdDMGr+bk/qKWtpXjhQf64O4PTgPB8wQDTZn7m0fQJH5VwJBAIDnGXiaoMRammmmOl6sYwar8APUMhRkCNqxzwiEokmwRsrR0GKuKtLKpRg/jNAAQbj2ajVihhgR7F3/04kc/jE= -----END RSA PRIVATE KEY-----` const PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv6trrrn/rOKXdoJFQMoR5KaINaOES+fg5tmTnuYuzvxCyib4//SSKzTtWmzTbhvINp7wZzniebootavN0MvQuGmnstVI6mHd4lbqbjvF35q/97B03nOkfF9B2Z7kP37FPLkRGBEBVHwRXGbYjc9k6l34yVzFwHk6V3Ogmyji3twIDAQAB" + "\n-----END PUBLIC KEY-----"; function longDecrypt(privateKey, msg) { // Format the private key privateKey = privateKey.match(/.{1,64}/g).join('\n'); privateKey = `-----BEGIN RSA PRIVATE KEY-----\n${privateKey}\n-----END RSA PRIVATE KEY-----`; // Decode the base64 message const bufferMsg = Buffer.from(msg, 'base64'); const length = bufferMsg.length; const defaultLength = 128; const key = new NodeRSA(privateKey, 'pkcs1'); key.setOptions({ encryptionScheme: 'pkcs1' }); let offset = 0; let res = []; while (length - offset > 0) { if (length - offset > defaultLength) { res.push(key.decrypt(bufferMsg.slice(offset, offset + defaultLength))); } else { res.push(key.decrypt(bufferMsg.slice(offset))); } offset += defaultLength; } return Buffer.concat(res).toString('utf8'); } function verifyWebhook() { const parsedData = {"meta":{"success":true,"code":"0000","message":"Request Success"},"data":{"merchantNo":"AC202299319","merchantOrderNo":"DS202412311005240317","orderNo":"R08OC0241231100525384624557803","currency":"JPY","payType":"JAPAN_PAY","orderAmount":10000,"paidAmount":null,"orderFee":700,"payModel":"BankTransfer","orderStatus":"PENDING","webUrl":null,"page":null,"orderTime":1735610725000,"finishTime":0,"sign":"V0EZCULoPBG7q8CuWxSnAkTnigjPbX49IquVzqH8TZ2Kp+SYJmXAmAWPLKPWWTQdvAw99T3PrkEMmutKfCE2zEay5uKhtHU8BY4T0phLr8cU3G9MTWNjp3AJ/dtJ6nh19/L20vis5anvj0aC4ShnEcIzfVeWtWszT+meu7LC4Js52C9vmGGKtPWUUbD6zV/+3YYnNxf/BIEBLOewWIaHccne6E37wbzjbHWczAPecka/E7KOGPyG2PPa67Y5ixsGUjhSD6RHHjbXKJatD8+vTa4BpwieQ4FZTF1dF2oCWJjVOLiB4ZSwMs4vRf9bb0GhWmJuf1N45eWWJkMRJ+392A==","remark":"","errorMessage":null,"descriptor":null},"sign":"589092dbe5aca882cfcc409d1f868d0e"}; const dataJson = parsedData.data; console.log("Decoded data:", JSON.stringify(dataJson, null, 2)); // 提取签名 const sign = dataJson.sign; delete dataJson.sign; console.log("Signature:", sign); // 生成待签名的字符串 function createSortedDataString(data) { const validKeys = [ "merchantNo", "merchantOrderNo", "orderNo", "currency", "orderAmount", "orderFee", "payModel", "orderStatus", "payType", ]; const sortedData = Object.keys(data) .filter((key) => validKeys.includes(key)) .sort() .map((key) => `${key}=${data[key]}`) .join("&"); return sortedData; } const signStr = createSortedDataString(dataJson); console.log("String to be signed:", signStr); // 验证签名 try { const verify = createVerify("SHA256"); verify.update(signStr); verify.end(); // const isVerified = verify.verify(PRIVATE_KEY, sign, "base64"); const isVerified = longDecrypt(PRIVATE_KEY, sign); console.log(58, isVerified); if (isVerified) { console.log("Verification passed"); return true; } else { console.log("Verification failed"); return false; } } catch (error) { console.error(`Decryption error: ${error.message}`); return false; } } verifyWebhook();