1/* 2* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15 16import cryptoFramework from '@ohos.security.cryptoFramework'; 17import util from '@ohos.util'; 18 19export enum PayResult { 20 SUCCESS = 200, 21 FAIL = 400, 22 ERROR = 600, 23} 24 25export interface User { 26 name: string, 27 payPassword: string, 28} 29 30const TAG = 'PayServer'; 31const TEXT_DECODER = util.TextDecoder.create('utf-8', { ignoreBOM: true }); 32const TEXT_ENCODER = new util.TextEncoder(); 33const SIGNER_INPUT = { data: TEXT_ENCODER.encodeInto('This is a test') }; 34const BASE64 = new util.Base64Helper(); 35// 支付服务端私钥 36const PAY_PRI_KEY = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMMWX1SJUPCshS1NIVVpqkaAfu/baUGqebuSo6NR00JokT54FWEJVPYrcrKQ+4TjGC0p6PavL7YeZ7kxBplnHunE2RcTo/r3LebZVunUqcWCxe1ZiV0YD++uZtegOEpTgd2w8Lib72+wQt68WO43I40wwySUX+X7dF1nSDNGA6YnAgMBAAECgYACZjYJ7h5mt1hz9CzixgfoEhB9lq82tYgFvInyqkD04iBXKlbo+Jpo5KPmek39lmVnuMo6rnDhxoH0DxxLqq8An4Hk6f/G1Eyc681sEicuas4zanpGWtPA3Y+an9ZwwTolVIkiJw6nM4hz8QdEeiFK34Bfl28dz9kg89ZrVomlwQJBAOEJPtA7QPwSuxix2E+BsPVNg/EqXgs+9HoyF+lrH8to5gTAZSjydT03d6FUZOZBsgPB/hL+Avh5YTUjhBV6khcCQQDd7jPFabvcyr5cKyS2TqYGmqTnhDX3LxgB35GE6jLlMO3teIY1HUsQsV2946lE4s7aqcalXa37Dw7yLxwlbGZxAkAggA5TUotzHF1rFpxP90IQW26X0O+eHix+zWdIrdD8tpypyQOTI1ktSyp64U5lNs233zeLlKXnLtiMLSHxXC9nAkAPbZvTwYH5225YYfdvZRBNrTqBjcNip7d3id9H6jAXlsszkwlhb+PkCTCHHuiJjWrr8JmKrXSG24kidPvz7hFBAkABQhnS1b3O4IIs5rdQTwcgBpzUk76csUQFB35g0IMV4jeHE7+84rNJDQ8hgStmyQvrLH8bBjX3xftxvj+q57cd'; 37// 商户服务端公钥 38const MERCHANT_PUB_KEY = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/4Xcag3k5SBGX52KduDPcYBSEanwpo85kzGceENvQkhG0UinwwxSttkXv9os1pikfChaD5vR2BhXsco54SC/rA=='; 39// 支付客户端私钥 40const PAY_CLIENT_PRI_KEY = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPvx0A4ex864EDiA8wDwY7/kqVDjzvsoC9pOSkkgMCRoBuWEADHiYoZrgrg9NLtPHONd0SD8Jk4B2eqym4ylB/bk87Jy4bbIdajeM86tvuS2R/RqPlOdFbeRoGFnlPITozGdQImH4eRfwRCnpYZqooIHDkPUWD2gDSuBmKCLqcP/AgMBAAECgYEAlrVgsoGhHjwmn9YrBp3F3Y0H53ZOYxjidjUs5K9XfP+pWHPstepo62W2bUVXnNBHRI7jQWrz8ufSlj0/JRO3Pb6CJp4u3Qw4ty/GAXtNUaaEb8Ll0SFkwu7TiUkHCEjnjF/aCkFVOAxwa2RT0GWs1uj+uqF7KyMylL4RZCyAnCkCQQD+74SDaTomcNHzPpVXyumZpmIxWpkP6GbcA0yjV3aw+K7IIHs20cYiNRXWw51Uh1aHTwqd8+/Ywq6IP9VHZT27AkEA/P8ZIoUZ/QsvIu0eUZRE9JaB4bcfD8RUGetqZhZA6J6Nd6uJ1nut/XG0JGa4wqSqBWGs8BBV6aDNuJzrzOYMjQJBAMMMwphAhEsw+pFfCqhXCY+Ta4FTTdSL/VbL93Dp1FfmjON1ZpA0w6EceI8Or2si+SMhaIAdSR7RJPP90tKDNU0CQExxX8zYXsPgjzuEXfbUUAl/OHtU82O2NJsoUJvL+YzP63rPL/TIpgfARWgCSa02R9EcdD6NEQhoeABiGbVthTkCQF8gsjNa6KIpfqEf4+DZFNO2o28ELyniY4O6xUKHWfiU7vKxRQ2DFYQ8Hv9Q07HB69kXc0p/XLJxjpX0K/Wpn2k='; 41const TEST_USER: User = { 42 name: 'test', 43 payPassword: '123456', 44}; 45const HEXADECIMAL = 36; 46const CONTAINS_LETTERS = 2; 47const MIN_LENGTH = 2; 48const INDEX_ZERO = 0; 49 50export class PayServer { 51 private orderString: string; 52 private merchantKey: cryptoFramework.KeyPair; 53 private payKey: cryptoFramework.KeyPair; 54 private payClientKey: cryptoFramework.KeyPair; 55 private static instance: PayServer; 56 57 private constructor() { 58 } 59 60 public static getInstance(): PayServer { 61 if (!PayServer.instance) { 62 PayServer.instance = new PayServer(); 63 } 64 return PayServer.instance; 65 } 66 67 public async generatePayOrder(body: string): Promise<string> { 68 if (!this.payKey) { 69 let rsaGenerator = cryptoFramework.createAsyKeyGenerator('RSA1024|PRIMES_2'); 70 this.payKey = await rsaGenerator.convertKey(null, { data: BASE64.decodeSync(PAY_PRI_KEY) }); 71 } 72 let decoder = cryptoFramework.createCipher('RSA1024|PKCS1'); 73 await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, this.payKey.priKey, null); 74 let data = await decoder.doFinal({ data: BASE64.decodeSync(body) }); 75 let bodyStr = TEXT_DECODER.decodeWithStream(data.data); 76 this.orderString = bodyStr + '&orderId=' + Array.from({ 77 length: 17 78 }, () => Math.random().toString(HEXADECIMAL)[CONTAINS_LETTERS]).join('').toUpperCase(); 79 return this.orderString; 80 } 81 82 public async pay(orderString: string, userName: string, password: string): Promise<PayResult> { 83 let temArr = orderString.split('&signer='); 84 if (temArr.length < MIN_LENGTH || temArr[INDEX_ZERO] !== this.orderString) { 85 return PayResult.ERROR; 86 } 87 if (!this.merchantKey) { 88 let eccGenerator = cryptoFramework.createAsyKeyGenerator('ECC256'); 89 this.merchantKey = await eccGenerator.convertKey({ data: BASE64.decodeSync(MERCHANT_PUB_KEY) }, null); 90 } 91 let verifyer = cryptoFramework.createVerify('ECC256|SHA256'); 92 await verifyer.init(this.merchantKey.pubKey); 93 let verifyOk = await verifyer.verify(SIGNER_INPUT, { data: BASE64.decodeSync(temArr[1]) }); 94 if (!verifyOk) { 95 return PayResult.ERROR; 96 } 97 if (!this.payClientKey) { 98 let rsaGenerator = cryptoFramework.createAsyKeyGenerator('RSA1024|PRIMES_2'); 99 this.payClientKey = await rsaGenerator.convertKey(null, { data: BASE64.decodeSync(PAY_CLIENT_PRI_KEY) }); 100 } 101 let decoder = cryptoFramework.createCipher('RSA1024|PKCS1'); 102 await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, this.payClientKey.priKey, null); 103 let userNameData = await decoder.doFinal({ data: BASE64.decodeSync(userName) }); 104 if (TEST_USER.name !== TEXT_DECODER.decodeWithStream(userNameData.data)) { 105 return PayResult.FAIL; 106 } 107 let passwordData = await decoder.doFinal({ data: BASE64.decodeSync(password) }); 108 if (TEST_USER.payPassword !== TEXT_DECODER.decodeWithStream(passwordData.data)) { 109 return PayResult.FAIL; 110 } 111 return PayResult.SUCCESS; 112 } 113}