Making an API Request - Trade Finance V3
Implementation Guide
On this page
This page will help you to:
- Prepare an API request payload and perform payload encryption
- Generate and sign a client token (JWT)
- Steps required to process a response
Making an API Request
For each request, prepare the following:
- Prepare the plain HTTP request body in JSON structure.
- Encrypt the HTTP request body using HSBC's Public Key.
- Generate Client Token (JWT).
- Add the Signed JWT (JWS) in the relating Authorization request header.
- Add Correlation ID header to uniquely identify the request in your system and submit.
The following section contains an implementation guide with examples.
Step 1 - Preparing unencrypted request
- 1.1 Constructing the JSON Schema according to the corresponding API reference document.
-
- Here is an example of the basic structure of the request JSON Schema.
{ "data": { "paramKey001": "paramValue001", "paramKey002": "paramValue002", ... } } - Code Example:
JSONObject requestJson = new JSONObject(); requestJson.put("paramKey001", "paramValue001); requestJson.put("paramKey002", "paramValue002); ...
- Here is an example of the basic structure of the request JSON Schema.
- 1.2 Converting the JSON Schema into JSON String Format
-
String textToEncrypt = {"data":{"paramKey001": "paramValue001","paramKey002": "paramValue002",...}}Request body examples are provided against each end-point in the API reference documentation - see Endpoints menu.
Category API References Trade Finance
Step 2 - Encrypt the request body
- 2.1 Loading Bank Public Keys
-
Steps
- Declares a
Stringwhich points to the key path and name of bank public key stored in your system. - Retrieves a list of Bank PGP Public Keys via
readPublicKey().
String bankPgpPublicKeyFileName = "%BANK_PUBLIC_KEY_PATH_AND_NAME_IN_YOUR_SYSTEM%"; List<PGPPublicKey> bankPgpPublicKeys = readPublicKey(bankPgpPublicKeyFileName);Code Example
public List<PGPPublicKey> readPublicKey(String fileName) { try { InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName)); InputStream decoderStream = PGPUtil.getDecoderStream(inputStream); PGPPublicKeyRingCollection ringCollection = new PGPPublicKeyRingCollection(decoderStream, new JcaKeyFingerprintCalculator()); PGPPublicKey pgpPublicKey = null; List<PGPPublicKey> pgpPublicKeys = new ArrayList<PGPPublicKey>(); for (PGPPublicKeyRing ring : ringCollection) { for (Iterator<PGPPublicKey> it = ring.getPublicKeys(); it.hasNext(); ) { pgpPublicKey = it.next(); pgpPublicKeys.add(pgpPublicKey); } return pgpPublicKeys; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (PGPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } - Declares a
- 2.2 Loading Client Private Keys
-
Steps
- Declares a
Stringwhich consists of your (client) private key's password. - Declares a
Stringwhich points to the key path and name of bank public key stored in your system. - Retrieves a list of Client PGP Secret keys via
readSecretKey(). - Extracts the
PGPPrivateKeyfrom one of the outputtedList<PGPSecretKey>. - Retrieves PGP Key ID from the above outputted
PGPPrivateKey.
String clientPgpPrivateKeyFileName = "%CLIENT_PRIVATE_KEY_PATH_AND_NAME_IN_YOUR_SYSTEM%"; String clientPrivateKeyPassPhrase = "%CLIENT_PRIVATE_KEY_PASSWORD%" List<PGPSecretKey> clientPgpSecretKeys = readSecretKey(clientPgpPrivateKeyFileName); PGPPrivateKey clientPgpPrivateKey = clientPgpSecretKey[0].extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().build(clientPrivateKeyPassPhrase); String clientPgpKeyId = (Long.toHexString(clientPgpPrivateKey.getKeyID()).toUpperCase());Code Example
public List<PGPSecretKey> readSecretKey(String fileName) { try { InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName)); InputStream decoderStream = PGPUtil.getDecoderStream(inputStream); PGPSecretKeyRingCollection ringCollection = new PGPSecretKeyRingCollection(decoderStream, new JcaKeyFingerprintCalculator()); PGPSecretKey pgpSecretKey = null; List<PGPSecretKey> pgpSecretKeys = new ArrayList<PGPSecretKey>(); for (PGPSecretKeyRing ring : ringCollection) { for (Iterator<PGPSecretKey> it = ring.getSecretKeys(); it.hasNext(); ) { pgpSecretKey = it.next(); pgpSecretKeys.add(pgpSecretKey); } return pgpSecretKeys; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (PGPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } - Declares a
- 2.3 Generate the encrypted Request Payload
-
Steps
- Converts the
textToEncrypt(JSON String prepared in Step 1) toByteArrayInputSteam - Encrypts the above stream using bank public key.
- Preferably, adds signature with (your) client's private key to the above encrypted data with compressions.
- Base64 Encodes the above encrypted data.
- Wraps the Base64 Strings into JSON Format.
String encryptedRequestBase64 = encryptAndAddSignature(textToEncrypt, bankPgpPublicKeys[0], clientPgpPrivateKey); //String encryptedRequestBase64 = encryptWithoutSignature(textToEncrypt, bankPgpPublicKey[0]); String requestPayload = "{\"encryptedRequestBase64\":\"" + encryptedRequestBase64 + "\"}";Code Example
// Encrypt and sign the request payload public String encryptAndAddSignature(String textToEncrypt, PGPPublicKey bankPublicKey, PGPPrivateKey clientPrivateKey) { if (StringUtils.isBlank(textToEncrypt)) { return ""; } ByteArrayOutputStream xout = new ByteArrayOutputStream(); ByteArrayInputStream inputStream = new ByteArrayInputStream(textToEncrypt.getBytes()); OutputStream out = (OutputStream) xout; out = new ArmoredOutputStream(xout); try { PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom( new SecureRandom()) .setProvider(new BouncyCastleProvider())); encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(bankPublicKey).setProvider(new BouncyCastleProvider())); OutputStream encryptedOut = encGen.open(out, new byte[inputStream.available()]); PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); OutputStream compressedData = comData.open(encryptedOut); PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder( clientPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA512).setProvider(new BouncyCastleProvider())); sGen.init(PGPSignature.BINARY_DOCUMENT, clientPrivateKey); Iterator<String> it = bankPublicKey.getUserIDs(); if (it.hasNext()) { PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); spGen.setSignerUserID(false, it.next()); sGen.setHashedSubpackets(spGen.generate()); } sGen.generateOnePassVersion(false).encode(compressedData); // bOut PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open(compressedData, PGPLiteralData.BINARY, "Sample-Data", new Date(), new byte[inputStream.available()]); //bOut byte[] data = IOUtils.toByteArray(inputStream); lOut.write(data); sGen.update(data); lOut.close(); lGen.close(); sGen.generate().encode(compressedData); comData.close(); compressedData.close(); encryptedOut.close(); encGen.close(); out.close(); } catch (PGPException e) { if (e.getUnderlyingException() != null) { log.error("A PGPException occurred in encrpytAndSignRequest:" + e.getUnderlyingException().getMessage()); } } catch (Exception e) { log.error("An Exception occurred in encrpytAndSignRequest:" + e.getMessage()); } return Base64.toBase64String(xout.toByteArray()); }// Encrypt the payload without signature public static String encryptWithoutSignature(String textToEncrypt, PGPPublicKey bankPublicKey) { if (StringUtils.isBlank(textToEncrypt)) { return ""; } ByteArrayOutputStream xout = new ByteArrayOutputStream(); ByteArrayInputStream inputStream = new ByteArrayInputStream(textToEncrypt.getBytes()); OutputStream out = new ArmoredOutputStream(xout); OutputStream encryptedOut = null; OutputStream lOut = null; try { PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom( new SecureRandom()) .setProvider(new BouncyCastleProvider())); encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(bankPublicKey).setProvider(new BouncyCastleProvider())); encryptedOut = encGen.open(out, new byte[inputStream.available()]); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); lOut = lGen.open(encryptedOut, PGPLiteralData.BINARY, "Sample-Data", new Date(), new byte[inputStream.available()]); byte[] data = IOUtils.toByteArray(inputStream); lOut.write(data); lOut.close(); lGen.close(); encryptedOut.close(); encGen.close(); out.close(); }catch (IOException e) { e.printStackTrace(); } catch (PGPException e) { e.printStackTrace(); } return Base64.toBase64String(xout.toByteArray()); } } - Converts the
Step 3 - Generate and Sign the Authorization Token
- 3.1 Token Definitions and fields
-
Below table defines the fields to be provided in the Authorization token.
Code Name Description In Example typ Token Type Type of Token - Always set as "JWT" JWT header JWT - MUST be set to “JWT” kid Key Id Key ID of Client PGP Key which will be used to sign this token JWT header 900864F8C11EB743 alg Signing Algorithm Algorithm Used to Sign this token JWT header PS256 ver Version Always set as 1.0 JWT header 1.0 - MUST be set as "1.0" jti JWT ID Unique ID to represent each API request's token. The format is UUID JWT payload 74760410-f963-11e8-b2a3-1bb26e1e5b69 iat Issue At Timestamp this toekn JWT payload 1565150776 sub Subject Who is sending this request. It will always be the Client Profile ID HSBC assigned to your platform. JWT payload Client/ PARTNER Profile ID aud Audience Who is receiving this request. It's a static value. JWT payload taas obo.sub On behalf of / subject This field is used to identify End Customer on your platform for this particular request. Required only if you are a partner of HSBC. JWT payload “obo” : { “sub” : "CUSTOMER001" } payload_hash Payload hash value Hash Value of the HTTP Request Payload. This is used by bank to verify your HTTP Request Payload are not tempered. JWT payload 1dab559f1f4bf4f3ca... payload_hash_alg Payload hash algorithm Algorithm Used to perform Payload Hashing JWT payload RSASHA256 - 3.2 Token Generations
-
Steps
- Generates
Hashmapfor JWT header according to fields specified above.- Specifies the signing algorithm of this token.
- Generates
Hashmapfor JWT claims according to fields specified above.- Specify
payloadHashAlgorithmand generate thepayloadHashwithrequestPayloadas input .
- Specify
- Convert Your (Client) Private Key from
PGPtoRSA. - Use
JwtBuilderto generate the token (compact).
// 3. Generate Authorization Token System.out.println("-----Start of #3. Generating Authorization Token-----"); String clientProfileId = activeProjectSettings.get("clientProfileId"); // API Profile ID Bank Assigned to you. String oboProfileId = activeProjectSettings.get("oboProfileId"); //Customer's ID on your platform. Input null if you are a Direct Client. HashMapString, Object> additionalTokenClaims = (HashMapString, Object>) apiSettings.get("additionalTokenClaims"); MapString, String> authTokens = generateAuthTokens(httpMethod, apiSchema, clientProfileId, oboProfileId, additionalTokenClaims, requestPayload, bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature); System.out.println("-----End of of #3. Generating Authorization Token-----\n");Code example
public static Map<String, String> generateAuthTokens(String httpMethod, String apiSchema, String clientProfileId, String onBehalfOf, Map<String, Object> additionalTokenClaims, String requestPayload, PGPPublicKey bankPgpPublicKey, PGPPrivateKey clientPgpPrivateKey, boolean xHsbcCryptoSignature) { try { System.out.println(" #a. Using HashMap to build token structure..."); HashMap<String, String> token = new HashMap<String, String>(); // header Map<String, Object> headers = new HashMap<String, Object>(); headers.put("kid", Long.toHexString(clientPgpPrivateKey.getKeyID()).toUpperCase()); headers.put("typ", "JWT"); headers.put("ver", "1.0"); headers.put("alg", TOKEN_ALG); // claims PrivateKey clientRsaPrivateKey = new JcaPGPKeyConverter().getPrivateKey(clientPgpPrivateKey); Map<String, Object> claims = new HashMap<String, Object>(); claims.put("jti", UUID.randomUUID().toString()); claims.put("iat", System.currentTimeMillis() / 1000); claims.put("sub", clientProfileId); //API Profile ID Bank Assigned to you during on-boarding if (apiSchema == (ApiSchema.Edge.SCHEMA_NAME)) { claims.put("aud", "baas"); // Obo, optional, only used when an API request is send on behalf of an End Customer if (onBehalfOf != null) { Map<String, Object> obo = new HashMap<String, Object>(); obo.put("sub", onBehalfOf); //End Customer ID, provided by your platform during on-boarding claims.put("obo", obo); } } else if (apiSchema == (ApiSchema.Gtrf.SCHEMA_NAME)) { claims.put("aud", "GTRF.MKT"); } //if (requestPayload != null) { if (httpMethod != HttpGet.METHOD_NAME) { String payloadHash = DatatypeConverter.printHexBinary(MessageDigest.getInstance(TOKEN_PAYLOAD_HASH_ALG).digest(requestPayload.getBytes())) .toLowerCase(); claims.put("payload_hash", payloadHash); claims.put("payload_hash_alg", clientRsaPrivateKey.getAlgorithm() + TOKEN_PAYLOAD_HASH_ALG.replace("-", "")); } // print token object printAuthToken(headers, claims); System.out.println(" #b. Building JWT and Signed by: " + clientRsaPrivateKey.toString()); JwtBuilder authorizationBuilder = Jwts.builder().setHeader(headers).setClaims(claims).signWith(clientRsaPrivateKey, SIGNATURE_ALG); //System.out.println(" #b. Building JWT and Signed by: " + Base64.getEncoder().encodeToString(pem.getEncoded())); //JwtBuilder jwtBuilder = Jwts.builder().setHeader(headers).setClaims(claims).signWith(pem, SIGNATURE_ALG); String authorization = authorizationBuilder.compact(); System.out.println(" #c. Generated Authorization Token:\nJWS " + authorization); if (apiSchema == (ApiSchema.Edge.SCHEMA_NAME)) { Map<String, Object> xHsbcTradeFinanceClaims = new HashMap<String, Object>() { { put("jti", claims.get("jti")); put("iat", claims.get("iat")); put("sub", claims.get("sub")); put("aud", claims.get("aud")); if (claims.containsKey("obo")) { put("obo", claims.get("obo")); } } }; for (Map.Entry<String, Object> entry : additionalTokenClaims.entrySet()) { if (entry.getKey() == "claimsNoEncrypt") { Map<String, Object> xHsbcTradeFinanceClaimsNoEncrypt = (Map<String, Object>) entry.getValue(); for (Map.Entry<String, Object> innerEntry : xHsbcTradeFinanceClaimsNoEncrypt.entrySet()) { xHsbcTradeFinanceClaims.put(innerEntry.getKey(), innerEntry.getValue()); } } if (entry.getKey() == "claimsToEncrypt") { Map<String, Object> xHsbcTradeFinanceClaimsToEncrypt = (Map<String, Object>) entry.getValue(); for (Map.Entry<String, Object> innerEntry : xHsbcTradeFinanceClaimsToEncrypt.entrySet()) { System.out.println(innerEntry.getValue().toString()); if (xHsbcCryptoSignature) { xHsbcTradeFinanceClaims.put(innerEntry.getKey(), encryptAndSign(innerEntry.getValue().toString(), bankPgpPublicKey, clientPgpPrivateKey)); } else { xHsbcTradeFinanceClaims.put(innerEntry.getKey(), encrypt(innerEntry.getValue().toString(), bankPgpPublicKey)); } } } } printAuthToken(headers, xHsbcTradeFinanceClaims); JwtBuilder xHsbcTradeFinanceBuilder = Jwts.builder().setHeader(headers).setClaims(xHsbcTradeFinanceClaims).signWith(clientRsaPrivateKey, SIGNATURE_ALG); String xHsbcTradeFinance = xHsbcTradeFinanceBuilder.compact(); System.out.println(" #c. Generated X-HSBC-Trade-Finance-Token:\nJWS " + xHsbcTradeFinance); token.put("xHsbcTradeFinance", xHsbcTradeFinance); } token.put("authorization", authorization); return token; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (PGPException e) { e.printStackTrace(); } return null; } public static void printAuthToken(Map<String, Object> header, Map<String, Object> claims) { System.out.println(" #a.1. Token Headers:"); for (Map.Entry<String, Object> entry : header.entrySet()) { System.out.println(" " + entry.getKey() + ":" + entry.getValue()); } System.out.println(" #a.2. Token Claims:"); for (Map.Entry<String, Object> entry : claims.entrySet()) { System.out.println(" " + entry.getKey() + ":" + entry.getValue()); } } - Generates
Step 4 - Add the Signed JWT (JWS) in HTTP Header
Adds the JWS to the Authorization header:
Authorization=JWS eyJ2ZXIiOiIxLjAiLCJraWQiOiJBNjI4RjhBRDY3NERCQz..
- Next, adds the remaining headers as per the API reference documentation for your specific end-point.
Step 5 - Adds remaining headers and submit
Steps:
- Follows the API reference documentation for your specific end-point to determine if any additional header values are required.
- Correlation ID is a UUID generated by your system to uniquely identify each request.
JSONObject requestHeaderJson = new JSONObject(); requestHeaderJson.put("Authorization", "JWS ".concat(token)); requestHeaderJson.put("X-HSBC-Request-Correlation-Id", String.valueOf(UUID.randomUUID())); requestHeaderJson.put("Content-Type", "application/json"); requestHeaderJson.put("X-HSBC-countryCode", "SG"); - Submits the API Request and retrieves the encrypted response string
String textToDecrypt = HttpClientUtil .doPost("%API_ENDPOINT_URL%", requestHeaderJson, requestPayload, token);Code Example:
public static String doPost(String apiEndpointUrl, JSONObject requestHeaderJson, String requestPayload, String token) throws Exception { System.out.println("\n#4 Preparing API Request... "); HttpPost post = new HttpPost(apiEndpointUrl); HttpHost proxyHost; RequestConfig config; System.out.println("#4.1 Request Header:"); for (Map.Entry<String, Object> entry : requestHeaderJson.entrySet()) { post.setHeader(entry.getKey(), (String) entry.getValue()); System.out.println(entry.getKey() + ":" + entry.getValue()); } System.out.println("\n#4.2 Request Body (bankPublicKeyEncryptedBase64):\n".concat(requestPayload)); post.setEntity(new StringEntity(requestPayload, "UTF-8")); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); String responseMessage = null; System.out.println("\n#4.3 Sending Request to HSBC API Endpoint ".concat(apiEndpointUrl)); switch (proxyMode) { case ("NoProxy"): config = RequestConfig.custom().build(); post.setConfig(config); try (CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslcsf).build()) { CloseableHttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); responseMessage = EntityUtils.toString(entity); break; } catch (Exception e) { e.printStackTrace(); } case ("HasProxy"): proxyHost = new HttpHost(ClientConfig.proxyHost, ClientConfig.proxyPort); config = RequestConfig.custom().setProxy(proxyHost).build(); post.setConfig(config); try (CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslcsf).build()) { CloseableHttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); responseMessage = EntityUtils.toString(entity); } catch (Exception e) { e.printStackTrace(); } break; case ("HasProxyWithCredentials"): proxyHost = new HttpHost(ClientConfig.proxyHost, ClientConfig.proxyPort); CredentialsProvider credsProvider = new BasicCredentialsProvider(); //Setting the credentials credsProvider.setCredentials(new AuthScope(ClientConfig.proxyHost, ClientConfig.proxyPort), new UsernamePasswordCredentials(ClientConfig.proxyUser, ClientConfig.proxyPassword)); config = RequestConfig.custom().setProxy(proxyHost).build(); post.setConfig(config); try (CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslcsf).setDefaultCredentialsProvider(credsProvider).build()) { CloseableHttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); responseMessage = EntityUtils.toString(entity); } catch (Exception e) { e.printStackTrace(); } break; default: throw new IllegalStateException("Unexpected value: " + proxyMode); } return responseMessage; }
Processing a Response
Responses are returned with the relating HTTP code and an encrypted response message.
- Processing a Response
-
Steps to process a response:
String decryptedMessage = decryptAndVerifySignature(textToDecrypt, bankPgpPublicKeys, clientPgpPrivateKeys);- For a successful response, the response message
textToDecryptwill be encrypted by (your) client's public key and Base64 encoded. - Uses Base64 representation to decode it.
- Then, decrypts it with (your) client private key.
- If you have added your signature during encryptions in Step 2, you will need to verify the signature from bank as well for successful decryption.
- The
decryptedMessageshall be in JSON Format, schema as per your chosen API Endpoint Reference.
Code Example
public String decryptAndVerifySignature(String textToDecrypt, List<PGPPublicKey> bankPublicKeys, List<PGPPrivateKey> clientPrivateKeys) { if (StringUtils.isBlank(textToDecrypt)) { return ""; } try { JcaKeyFingerprintCalculator keyFingerPrintCalculator = new JcaKeyFingerprintCalculator(); String epicStrNew = new String(Base64.decode(textToDecrypt)); BufferedInputStream dataStream = new BufferedInputStream(IOUtils.toInputStream(epicStrNew)); InputStream decoderStream = PGPUtil.getDecoderStream(dataStream); PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(decoderStream, keyFingerPrintCalculator); PGPEncryptedDataList pgpEncryptedDataList = (PGPEncryptedDataList) pgpObjectFactory.nextObject(); // find the matching public key encrypted data packet. PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData = null; // build decryptor factory PublicKeyDataDecryptorFactory dataDecryptorFactory = null; for (Object pgpEncData : pgpEncryptedDataList) { PGPPublicKeyEncryptedData pkEnc = (PGPPublicKeyEncryptedData) pgpEncData; for (PGPPrivateKey clientPrivateKey : clientPrivateKeys) { if (pkEnc.getKeyID() == clientPrivateKey.getKeyID()) { pgpPublicKeyEncryptedData = pkEnc; dataDecryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC") .build(clientPrivateKey); break; } } } if (pgpPublicKeyEncryptedData == null || dataDecryptorFactory == null) { // Public key used to encrypt data does not correspond to private key provided throw new IllegalStateException("matching encrypted data not found"); } InputStream clear = pgpPublicKeyEncryptedData.getDataStream(dataDecryptorFactory); PGPObjectFactory plainFact = new PGPObjectFactory(clear, new JcaKeyFingerprintCalculator()); Object message = plainFact.nextObject(); ByteArrayOutputStream actualOutput = new ByteArrayOutputStream(); PGPSignatureList signatureList = null; PGPOnePassSignatureList onePassSignatureList = null; PGPCompressedData compressedData; while (message != null) { if (message instanceof PGPCompressedData) { compressedData = (PGPCompressedData) message; plainFact = new PGPObjectFactory(compressedData.getDataStream(), keyFingerPrintCalculator); message = plainFact.nextObject(); } if (message instanceof PGPLiteralData) { // have to read it and keep it somewhere. Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput); } else if (message instanceof PGPOnePassSignatureList) { onePassSignatureList = (PGPOnePassSignatureList) message; } else if (message instanceof PGPSignatureList) { signatureList = (PGPSignatureList) message; } else { throw new PGPException("message unknown message type."); } message = plainFact.nextObject(); } actualOutput.close(); clear.close(); if (onePassSignatureList == null || signatureList == null) { throw new SignatureException("PGP Signatures not found."); } else { boolean signatureVerified = false; for (int i = 0; i < onePassSignatureList.size(); i++) { PGPOnePassSignature ops = onePassSignatureList.get(0); PGPSignature signature = signatureList.get(0); for (PGPPublicKey bankPublicKey : bankPublicKeys) { ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider(new BouncyCastleProvider()), bankPublicKey); ops.update(actualOutput.toByteArray()); if (ops.verify(signature)) { signatureVerified = true; break; } } } if (!signatureVerified) { throw new SignatureException("Signature verification failed"); } } // check data decrypts okay if (!pgpPublicKeyEncryptedData.verify()) { throw new RuntimeException("Enc data is invalid!"); } return actualOutput.toString(); } catch (PGPException | IOException | SignatureException e) { e.printStackTrace(); } return ""; }public String decrypt(String textToDecrypt, PGPPrivateKey pgpPrivateKey, Response response) { if (StringUtils.isBlank(textToDecrypt)) { return ""; } try { JcaKeyFingerprintCalculator keyFingerPrintCalculator = new JcaKeyFingerprintCalculator(); String epicStrNew = new String(Base64.decode(textToDecrypt)); BufferedInputStream dataStream = new BufferedInputStream(IOUtils.toInputStream(epicStrNew)); InputStream decoderStream = PGPUtil.getDecoderStream(dataStream); PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(decoderStream, keyFingerPrintCalculator); PGPEncryptedDataList pgpEncryptedDataList = (PGPEncryptedDataList) pgpObjectFactory.nextObject(); // find the matching public key encrypted data packet. PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData = null; // build decryptor factory PublicKeyDataDecryptorFactory dataDecryptorFactory = null; for (Object pgpEncData : pgpEncryptedDataList) { PGPPublicKeyEncryptedData pkEnc = (PGPPublicKeyEncryptedData) pgpEncData; for (PGPPrivateKey clientPrivateKey : clientPrivateKeys) { if (pkEnc.getKeyID() == clientPrivateKey.getKeyID()) { pgpPublicKeyEncryptedData = pkEnc; dataDecryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC") .build(clientPrivateKey); break; } } } if (pgpPublicKeyEncryptedData == null || dataDecryptorFactory == null) { // Public key used to encrypt data does not correspond to private key provided throw new IllegalStateException("matching encrypted data not found"); } InputStream clear; Object message; try { clear = pgpPublicKeyEncryptedData.getDataStream(dataDecryptorFactory); PGPObjectFactory plainFact = new PGPObjectFactory(clear, new JcaKeyFingerprintCalculator()); message = plainFact.nextObject(); } catch (PGPException | IOException e) { log.error("An error occurred during decryption. Exception message:\n {}", e.getMessage()); return null; } ByteArrayOutputStream actualOutput = new ByteArrayOutputStream(); try { Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput); actualOutput.close(); clear.close(); } catch (IOException e) { log.warn("An error occurred when generating the decrypted content. Exception message:\n {}", e.getMessage()); return null; } // check data decrypts okay try { if (!pgpPublicKeyEncryptedData.verify()) { log.warn("Enc data is invalid!"); } } catch (PGPException | IOException e) { log.warn("Unable to verify the decrypted response. Exception message:\n {}", e.getMessage()); } return actualOutput.toString(); } - For a successful response, the response message
Using Sample Java Code
- Step 1 - Configure Sample JAVA Client
-
- Download the Trade Finance sample java client.
- JDK: 1.8
- Maven 3
- Import
wsit-sample-code.zipas your maven project. - Set under
src\main\resources\projects.json{ "projects": [ { "name": "Project Name", //The name must be the same as the folder name where you store your keys "clientProfileId": "EvVM4uo3T53Oody0QAl22xie1CueuHnS", //Input Client's HSBC API Profile "oboProfileId": "PC000006001", //Customer Identifier from your platform, Optional, only used for B2B2B integration. "clientSecret": "pU7MG5qt6YStBHuC", //Only used for sandbox, obtained from Dev Hub Project on develop.hsbc "organizationId": "24", //Only used for sandbox, obtained from Dev Hub Project on develop.hsbc "pgpKeys": { "fileNames": { "bankPublic": "hsbc-public.key", //Input the name of bank public key given "clientPublic": "client-public.key", //Input the name of client public key you generated (If you are using sandbox, use the key sandbox generated for your) "clientPrivate": "client-private.key" //Input the name of client private key you generated (If you are using sandbox, use the key sandbox generated for your) }, "clientPrivateKeyPassphrase": "1password" //Input the passPhrase of client private key }, "xHsbcCryptoSignature": true, //Input true if you are using API Version > 3 "targetHost": "SANDBOX", //Input the environment you would like to connect to. Values are "SANDBOX", "UAT", "PRODUCTION" "clientHostingRegion": "SG", //Input your Hosting Region "active": true //You can add multiple projects, hence this is the flag to choose which project you are using } ] } - Set under src\main\config\ClientConfig.java:
/** * JSON Web Token */ public static final SignatureAlgorithm TOKEN_ALG = SignatureAlgorithm.PS256; public static final String TOKEN_AUD = "taas"; // Keep this for Audience is Trade Finance public static final String TOKEN_PAYLOAD_HASH_ALG = "SHA-256"; //Your Request Payload Hashing Algorithm - Create a folder with your desired project name, place the keys downloaded form Dev Hub Project: under:
src\main\resources\keys\{project name}- client private key:
client-private.asc - client public key:
client-public.asc - hsbc public key:
hsbc-public.asc
- client private key:
- Download the Trade Finance sample java client.
- Step 2 - Testing API Connectivity
-
To test API Connectivity, let's try this API - SupplyChainFinance$V3$EnquireInvoiceSummaryList - which help corporates to fetch approved invoices which were submitted from your buyer/ seller to HSBC.
In this scenario, since there isn't any invoices submitted yet, we will expect no data are found.- Run SupplyChainFinance$V3$EnquireInvoiceSummaryList under
src\main\java\api\wsit\product_request\- To change your querying parameters, edit the key and values under REQUEST_URI_PARAMETERS HashMap

- To change your querying parameters, edit the key and values under REQUEST_URI_PARAMETERS HashMap
- From the terminal, observe the API Journey:
- It reads the c;ient and bank key pairs from the project resource folder (specified in project.json)

- A JSON Web Token will be generated as your digital signature and included in the header of your request.

- Observe #6 Decrypting Response Message
- If you get a decrypted response message in JSON in #6.1, congratulations! You have your Authentication setup correct and successfully connected to the HSBC API!
- The API response shows that no data found as expected.
- It reads the c;ient and bank key pairs from the project resource folder (specified in project.json)
Congratulation! You have managed the connectivity to HSBC API.
For API usage for specific products and endpoints, please refer to Making an API Request/ Sandbox Access under Documentation for the respective APIs.
- Run SupplyChainFinance$V3$EnquireInvoiceSummaryList under