📄 valuelinkapi.java
字号:
/** * Creates a Map of initial request values (MerchID, AltMerchNo, Modes, MerchTime, TermTxnNo, EncryptID) * Note: For 2010 (assign working key) transaction, the EncryptID will need to be adjusted * @return Map containing the inital request values */ public Map getInitialRequestMap(Map context) { Map request = new HashMap(); // merchant information request.put("MerchID", merchantId + terminalId); request.put("AltMerchNo", props.get("payment.valuelink.altMerchantId")); // mode settings String modes = (String) props.get("payment.valuelink.modes"); if (modes != null && modes.length() > 0) { request.put("Modes", modes); } // merchant timestamp String merchTime = (String) context.get("MerchTime"); if (merchTime == null) { merchTime = this.getDateString(); } request.put("MerchTime", merchTime); // transaction number String termTxNo = (String) context.get("TermTxnNo"); if (termTxNo == null) { termTxNo = delegator.getNextSeqId("ValueLinkKey").toString(); } request.put("TermTxnNo", termTxNo); // current working key index request.put("EncryptID", this.getWorkingKeyIndex()); if (debug) { Debug.log("Created Initial Request Map : " + request, module); } return request; } /** * Gets the cached value object for this merchant's keys * @return Cached GenericValue object */ public GenericValue getGenericValue() { GenericValue value = null; try { value = delegator.findByPrimaryKeyCache("ValueLinkKey", UtilMisc.toMap("merchantId", merchantId)); } catch (GenericEntityException e) { Debug.logError(e, module); } if (value == null) { throw new RuntimeException("No ValueLinkKey record found for Merchant ID : " + merchantId); } return value; } /** * Reloads the keys in the object cache; use this when re-creating keys */ public void reload() { this.kek = null; this.mwk = null; this.mwkIndex = null; } // using the prime and generator provided by valuelink; create a parameter object protected DHParameterSpec getDHParameterSpec() { String primeHex = (String) props.get("payment.valuelink.prime"); String genString = (String) props.get("payment.valuelink.generator"); // convert the p/g hex values byte[] primeByte = StringUtil.fromHexString(primeHex); BigInteger prime = new BigInteger(1, primeByte); // force positive (unsigned) BigInteger generator = new BigInteger(genString); // initialize the parameter spec DHParameterSpec dhParamSpec = new DHParameterSpec(prime, generator, 1024); return dhParamSpec; } // actual kek encryption/decryption code protected byte[] cryptoViaKek(byte[] content, int mode) { // open a cipher using the kek for transport Cipher cipher = this.getCipher(this.getKekKey(), mode); byte[] dec = new byte[0]; try { dec = cipher.doFinal(content); } catch (IllegalStateException e) { Debug.logError(e, module); } catch (IllegalBlockSizeException e) { Debug.logError(e, module); } catch (BadPaddingException e) { Debug.logError(e, module); } return dec; } // return a cipher for a key - DESede/CBC/NoPadding IV = 0 protected Cipher getCipher(SecretKey key, int mode) { byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 }; IvParameterSpec iv = new IvParameterSpec(zeros); // create the Cipher - DESede/CBC/NoPadding Cipher mwkCipher = null; try { mwkCipher = Cipher.getInstance("DESede/CBC/NoPadding"); } catch (NoSuchAlgorithmException e) { Debug.logError(e, module); return null; } catch (NoSuchPaddingException e) { Debug.logError(e, module); } try { mwkCipher.init(mode, key, iv); } catch (InvalidKeyException e) { Debug.logError(e, "Invalid key", module); } catch (InvalidAlgorithmParameterException e) { Debug.logError(e, module); } return mwkCipher; } protected byte[] getPinCheckSum(byte[] pinBytes) { byte[] checkSum = new byte[1]; checkSum[0] = 0; for (int i = 0; i < pinBytes.length; i++) { checkSum[0] += pinBytes[i]; } return checkSum; } protected byte[] getRandomBytes(int length) { Random rand = new Random(); byte[] randomBytes = new byte[length]; rand.nextBytes(randomBytes); return randomBytes; } protected SecretKey getMwkKey() { if (mwk == null) { mwk = this.getDesEdeKey(getByteRange(getMwk(), 8, 24)); } if (debug) { Debug.log("Raw MWK : " + StringUtil.toHexString(getMwk()), module); Debug.log("MWK : " + StringUtil.toHexString(mwk.getEncoded()), module); } return mwk; } protected SecretKey getKekKey() { if (kek == null) { kek = this.getDesEdeKey(getKek()); } if (debug) { Debug.log("Raw KEK : " + StringUtil.toHexString(getKek()), module); Debug.log("KEK : " + StringUtil.toHexString(kek.getEncoded()), module); } return kek; } protected SecretKey getDesEdeKey(byte[] rawKey) { SecretKeyFactory skf = null; try { skf = SecretKeyFactory.getInstance("DESede"); } catch (NoSuchAlgorithmException e) { // should never happen since DESede is a standard algorithm Debug.logError(e, module); return null; } // load the raw key if (rawKey.length > 0) { DESedeKeySpec desedeSpec1 = null; try { desedeSpec1 = new DESedeKeySpec(rawKey); } catch (InvalidKeyException e) { Debug.logError(e, "Not a valid DESede key", module); return null; } // create the SecretKey Object SecretKey key = null; try { key = skf.generateSecret(desedeSpec1); } catch (InvalidKeySpecException e) { Debug.logError(e, module); } return key; } else { throw new RuntimeException("No valid DESede key available"); } } protected byte[] getMwk() { return StringUtil.fromHexString(this.getGenericValue().getString("workingKey")); } protected byte[] getKek() { return StringUtil.fromHexString(this.getGenericValue().getString("exchangeKey")); } protected byte[] getPrivateKeyBytes() { return StringUtil.fromHexString(this.getGenericValue().getString("privateKey")); } protected Map parseResponse(String response) { if (debug) { Debug.log("Raw Response : " + response, module); } // covert to all lowercase and trim off the html header String subResponse = response.toLowerCase(); int firstIndex = subResponse.indexOf("<tr>"); int lastIndex = subResponse.lastIndexOf("</tr>"); subResponse = subResponse.substring(firstIndex, lastIndex); // check for a history table String history = null; List historyMapList = null; if (subResponse.indexOf("<table") > -1) { int startHistory = subResponse.indexOf("<table"); int endHistory = subResponse.indexOf("</table>") + 8; history = subResponse.substring(startHistory, endHistory); // replace the subResponse string so it doesn't conflict subResponse = StringUtil.replaceString(subResponse, history, "[_HISTORY_]"); // parse the history into a list of maps historyMapList = this.parseHistoryResponse(history); } // replace all end rows with | this is the name delimiter subResponse = StringUtil.replaceString(subResponse, "</tr>", "|"); // replace all </TD><TD> with = this is the value delimiter subResponse = StringUtil.replaceString(subResponse, "</td><td>", "="); // clean off a bunch of other useless stuff subResponse = StringUtil.replaceString(subResponse, "<tr>", ""); subResponse = StringUtil.replaceString(subResponse, "<td>", ""); subResponse = StringUtil.replaceString(subResponse, "</td>", ""); // make the map Map responseMap = StringUtil.strToMap(subResponse, true); // add the raw html back in just in case we need it later responseMap.put("_rawHtmlResponse", response); // if we have a history add it back in if (history != null) { responseMap.put("_rawHistoryHtml", history); responseMap.put("history", historyMapList); } if (debug) { Debug.log("Response Map : " + responseMap, module); } return responseMap; } private List parseHistoryResponse(String response) { if (debug) { Debug.log("Raw History : " + response, module); } // covert to all lowercase and trim off the html header String subResponse = response.toLowerCase(); int firstIndex = subResponse.indexOf("<tr>"); int lastIndex = subResponse.lastIndexOf("</tr>"); subResponse = subResponse.substring(firstIndex, lastIndex); // clean up the html and replace the delimiters with '|' subResponse = StringUtil.replaceString(subResponse, "<td>", ""); subResponse = StringUtil.replaceString(subResponse, "</td>", "|"); // test the string to make sure we have fields to parse String testResponse = StringUtil.replaceString(subResponse, "<tr>", ""); testResponse = StringUtil.replaceString(testResponse, "</tr>", ""); testResponse = StringUtil.replaceString(testResponse, "|", ""); testResponse = testResponse.trim(); if (testResponse.length() == 0) { if (debug) { Debug.log("History did not contain any fields, returning null", module); } return null; } // break up the keys from the values int valueStart = subResponse.indexOf("</tr>"); String keys = subResponse.substring(4, valueStart - 1); String values = subResponse.substring(valueStart + 9, subResponse.length() - 6); // split sets of values up values = StringUtil.replaceString(values, "|</tr><tr>", "&"); List valueList = StringUtil.split(values, "&"); // create a List of Maps for each set of values List valueMap = new ArrayList(); for (int i = 0; i < valueList.size(); i++) { valueMap.add(StringUtil.createMap(StringUtil.split(keys, "|"), StringUtil.split((String) valueList.get(i), "|"))); } if (debug) { Debug.log("History Map : " + valueMap, module); } return valueMap; } /** * Returns a new byte[] from the offset of the defined byte[] with a specific number of bytes * @param bytes The byte[] to extract from * @param offset The starting postition * @param length The number of bytes to copy * @return a new byte[] */ public static byte[] getByteRange(byte[] bytes, int offset, int length) { byte[] newBytes = new byte[length]; for (int i = 0; i < length; i++) { newBytes[i] = bytes[offset + i]; } return newBytes; } /** * Copies a byte[] into another byte[] starting at a specific position * @param source byte[] to copy from * @param target byte[] coping into * @param position the position on target where source will be copied to * @return a new byte[] */ public static byte[] copyBytes(byte[] source, byte[] target, int position) { byte[] newBytes = new byte[target.length + source.length]; for (int i = 0, n = 0, x = 0; i < newBytes.length; i++) { if (i < position || i > (position + source.length - 2)) { newBytes[i] = target[n]; n++; } else { for (; x < source.length; x++) { newBytes[i] = source[x]; if (source.length - 1 > x) { i++; } } } } return newBytes; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -