National Health AuthorityNHA Docs

Command Palette

Search for a command to run...

Payload Code Snippets

Prepare and process NHCX JWE payloads with reference Java snippets.

Use these snippets as a reference when you prepare an NHCX encrypted payload. Prepare the FHIR bundle from the correct NRCES profile first. Then add a protected header and encrypt the bundle.

Certificate cache

Store the receiver public certificate locally. Do not call /fetch/certs for each payload. Refresh the certificate cache on a planned schedule.

Payload parts

An NHCX JWE payload has 2 parts. Separate the parts with a dot in the serialized JWE value.

PartDescription
Protected headerContains NHCX routing, workflow, and crypto parameters.
FHIR bundleContains the encrypted FHIR bundle for the use case.

Protected header

Protected header example
{
  "alg": "RSA-OAEP-256",
  "enc": "A256GCM",
  "x-hcx-api_call_id": "bbea0ea1-2750-4ec8-8974-d3edc7030913",
  "x-hcx-workflow_id": "1",
  "x-hcx-request_id": "1113f541-6387-4c2a-ad3e-4bebc5a9fe36",
  "x-hcx-status": "request.initiated",
  "x-hcx-timestamp": "2023-08-02T14:57:40+0530",
  "x-hcx-sender_code": "1000000046@sbx",
  "x-hcx-recipient_code": "1000000109@sbx",
  "x-hcx-correlation_id": "3a2ba13b-04f5-4943-9b50-a1334e55c90e"
}

Base64url encode the protected header before you place it in the payload. Use the mandatory header list in Requests and Responses.

Encrypt a payload

Pass the protected headers, the FHIR bundle, and the receiver certificate path. Use the receiver public key for encryption.

Encrypt a JWE payload
private String encryptPayload(
    Map<String, Object> headers,
    Map<String, Object> payloadMain,
    String certificatePath) {
  logger.info("-- Encrypting payload --");
  JWEPayloadUtil jweRequest = new JWEPayloadUtil();
 
  try {
    String encryptedMsg = jweRequest.encryptRequestNew(
        KeyLoader.loadPublicKeyFromX509Certificate(new File(certificatePath)),
        headers,
        payloadMain);
    logger.info(String.format("-- Encrypted Payload --> %s", encryptedMsg));
    logger.info("-- Payload encrypted successfully --");
    return encryptedMsg;
  } catch (CertificateException | JOSEException | IOException e) {
    e.printStackTrace();
    logger.info("-- Error while encrypting payload --");
    return null;
  }
}

Build the JWE object

Use RSA-OAEP-256 for key management. Use A256GCM for content encryption.

Build and serialize the JWE object
public static final JWEAlgorithm KEY_MANAGEMENT_ALGORITHM = JWEAlgorithm.RSA_OAEP_256;
public static final EncryptionMethod CONTENT_ENCRYPTION_ALGORITHM = EncryptionMethod.A256GCM;
public static final EncryptionMethod CONTENT_DECRYPTION_ALGORITHM = EncryptionMethod.A256GCM;
 
public String encryptRequestNew(
    RSAPublicKey rsaPublicKey,
    Map<String, Object> headers,
    Map<String, Object> payload) throws JOSEException {
  JWEHeader jweHeader = new JWEHeader.Builder(
      KEY_MANAGEMENT_ALGORITHM,
      CONTENT_ENCRYPTION_ALGORITHM)
      .customParams(headers)
      .build();
 
  Payload jwePayload = new Payload(payload);
  JWEObject jweObject = new JWEObject(jweHeader, jwePayload);
  RSAEncrypter rsaEncrypter = new RSAEncrypter(rsaPublicKey);
  jweObject.encrypt(rsaEncrypter);
  return jweObject.serialize();
}

Load the public key

Read the X.509 certificate from a PEM file. Return the public key as an RSA key.

Load an RSA public key from a certificate
public static RSAPublicKey loadPublicKeyFromX509Certificate(File publicKeyFile)
    throws IOException, CertificateException {
  FileReader fileReader = new FileReader(publicKeyFile);
 
  try (PemReader pemReader = new PemReader(fileReader)) {
    PemObject pemObject = pemReader.readPemObject();
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    X509Certificate x509Certificate = (X509Certificate) certificateFactory
        .generateCertificate(new ByteArrayInputStream(pemObject.getContent()));
    return (RSAPublicKey) x509Certificate.getPublicKey();
  }
}

Decrypt a payload

Use the receiver private key for decryption. Read the JWE parts from the encrypted object map.

Decrypt a JWE payload
public Map<String, Object> decryptRequest(
    RSAPrivateKey rsaPrivateKey,
    Map<String, String> encryptedObject) throws ParseException, JOSEException {
  JWEObject jweObject = new JWEObject(
      new Base64URL(encryptedObject.get("protected")),
      new Base64URL(encryptedObject.get("encrypted_key")),
      new Base64URL(encryptedObject.get("iv")),
      new Base64URL(encryptedObject.get("ciphertext")),
      new Base64URL(encryptedObject.get("tag")));
 
  JWEDecrypter jweDecrypter = new RSADecrypter(rsaPrivateKey);
  jweObject.decrypt(jweDecrypter);
  return new HashMap<>(jweObject.getPayload().toJSONObject());
}

Sources

  • code-snippets-payload-preparation.md (NHCX sandbox portal)