Zero Access + HPKE

Introduction

Hybrid Public Key Encryption (HPKE) is a general-purpose specification which enables encrypting data against an asymmetric public key. It's often used to encrypt data between a sender and a receiver.

Trinsic supports HPKE to optionally provide an additional layer of security on top of Zero Access Encryption. When HPKE is configured and enabled, Session Results are HPKE-encrypted by Trinsic before being stored within a Session Data Vault. While stored in the vault, and during transmission to you, PII is encrypted such that only your private key can decrypt it.

Trinsic operates as the sender of data, encrypting data against your recipient public key.

HPKE increases the complexity of an integration with Trinsic, but offers the greatest level of data protection possible when paired with Zero Access Encryption.



Key Management

HPKE keys are currently managed and configured manually by Trinsic.

To configure an HPKE key on your account, reach out to Trinsic and provide us with your key in PEM or JWK form.

For testing and development, we offer a Self-Test API to test your implementation against encrypted bundles from Trinsic's API without configuring a public key ahead of time.


Core HPKE Implementation

Algorithms

HPKE is a general-purpose protocol which supports a large variety of cryptographic algorithms and curves. However, to simplify development and integration for languages or environments which do not yet have high-quality HPKE libraries available, Trinsic uses a minimal HPKE profile, with no variability in chosen algorithms.


Presently, all HPKE operations are performed using the following parameters:

ParameterValueNotes
ModeBase (0x00)Trinsic's API authentication and TLS certificate satisfy sender authentication requirements, so a Mode other than Base is not presently supported.
KEMDHKEM(P-256, HKDF-SHA-256) (0x0010 / 16)

Key Encapsulation Mechanism

This parameter determines the asymmetric algorithm used to derive a shared secret.

KDFHKDF-SHA256 (0x0001 / 1)

Key Derivation Function

This parameter determines the key derivation function used for various operations within HPKE.

AEADAES_128_GCM
(0x0001 / 1)

Authenticated Encryption with Associated Data

This parameter determines the symmetric encryption algorithm to use when encrypting/decrypting data within HPKE.

Sequence0

This parameter increases by 1 for each message sent within an HPKE session.

All Trinsic HPKE operations are single-shot, so this is always 0.


info Parameter

The info parameter is used to cryptographically bind a message with a context, ensuring that a recipient can only decrypt a message if it was encrypted with the same context. The sender (Trinsic) and receiver (your application) must each construct the info independently; decryption will fail if info differs in any way. This prevents a hypothetical attacker from swapping encrypted message contents.

The info parameter for Trinsic HPKE operations is a byte array containing a UTF-8-encoded string with the following structure:

trinsic-hpke:{version}:{domain}:{context}
trinsic-hpke:1:session-results:6725f68a-5501-80c2-9c85-c5f36fbc602a
ParameterDescriptionExample Value
version

Version of the Trinsic HPKE Scheme.

Always 1.

1
domainThe kind of message being encoded.session-results
contextFurther context information, in a domain-specific structure.6725f68a-5501-80c2-9c85-c5f36fbc602a

See below for a list of all possible values for domain and their corresponding context structures.


Encryption Domains

Each different kind of message that Trinsic encrypts via HPKE is encrypted using a different domain; further, each domain has additional context defined for it.

The following table lists all domain values, as well as their context templates.

DomainContext TemplateMessage Data ModelNotes
session-results{sessionId}IdentityDataUsed for Session Results
attachment-contents{sessionId}:{attachmentId}GetAttachmentResponseUsed for Attachments
customer-self-test{infoSuffix}N/AUsed for messages encrypted using the Self-Test APIs

Example: When decrypting Session Results for a Session with ID 772836df-9312-70ad-2c35-c6fd6fac613f:

  • Domain: session-results
  • Context: 772836df-9312-70ad-2c35-c6fd6fac613f
  • Full Info String: trinsic-hpke:1:session-results:772836df-9312-70ad-2c35-c6fd6fac613f

Example: When decrypting an Attachment with ID 5f2c3276-a04e-44c9-b503-75f9dff5e08d for a Session with ID b4675c1f-5602-415a-86df-45d3b376402e:

  • Domain: attachment-contents
  • Context: b4675c1f-5602-415a-86df-45d3b376402e:5f2c3276-a04e-44c9-b503-75f9dff5e08d
  • Full Info String: trinsic-hpke:1:attachment-contents:b4675c1f-5602-415a-86df-45d3b376402e:5f2c3276-a04e-44c9-b503-75f9dff5e08d

Trinsic HPKE Bundle

When HPKE is enabled on your account, Trinsic does not return raw identityData or attachment content from our APIs. Instead, we return HPKE-encrypted data, in the form of a TrinsicHPKEBundle:

{
    // Always 1
    "trinsicHpkeVersion": 1,

    // HPKE parameters and metadata.
    "metadata": {
        // HPKE Mode. Always `0`.
        "mode": 0,

        // HPKE Key Encapsulation Mechanism. Always `16`.
        "kem": 16,

        // HPKE Key Derivation Function. Always `1`.
        "kdf": 1,

        // HPKE AEAD. Always `1`.
        "aead": 1,

        // Base64-encoded SHA256 hash of `info`. Useful for debugging only.
        "infoHash": "K5iric4zDBxK2mND77jy5Iu9N1K0K+1YXrYMtXbQvJQ=",

        // Base64-encoded SHA256 hash of the encoded recipient public key point.
        "recipientPublicKeyHash": "mmTQVVYT13zL9eA4HoijLh+FwUzgRC7tV5CaHji+hcI=",

        // Base64-encoded JWK thumbprint of the recipient public key
        "recipientPublicKeyJwkThumbprint": "4yE7QV4mtViQzZQ0LinkAj2uYVTOf0TxC21w-HccbnI",
    },

    // The base64-coded public key point of the ephemeral public key.
    // Use as the `enc` parameter for HPKE.
    "ephemeralSenderPublicKey": "BMV9NqGWIe00D0Z8z88uN72JC1hR6DaBciSsVDmjGiOLCQLrjRptF1wGrMRpLlmc4m02R4CssDS586eRLItU2yA=",

    // The base64-encoded ciphertext.
    // Use as the `ct` parameter for HPKE.
    "ciphertext": "6/KCzUhwWaAoAioz0z6AU/HbZX8="
}
{
    "trinsicHpkeVersion": 1,
    "metadata": {
        "mode": 0,
        "kem": 16,
        "kdf": 1,
        "aead": 1,
        "infoHash": "K5iric4zDBxK2mND77jy5Iu9N1K0K+1YXrYMtXbQvJQ=",
        "recipientPublicKeyHash": "mmTQVVYT13zL9eA4HoijLh+FwUzgRC7tV5CaHji+hcI="
    },
    "ephemeralSenderPublicKey": "BMV9NqGWIe00D0Z8z88uN72JC1hR6DaBciSsVDmjGiOLCQLrjRptF1wGrMRpLlmc4m02R4CssDS586eRLItU2yA=",
    "ciphertext": "6/KCzUhwWaAoAioz0z6AU/HbZX8="
}


Self-Test API

To test your HPKE implementation against Trinsic's API without needing to configure any keys, use the Self-Test API.

POST https://api.trinsic.id/api/valpha/hpke-test
Authorization: Bearer {TrinsicApiToken}

{
    "data": "{dataToEncryptBase64}",
    "infoSuffix": "{32RandomCharacters}",
    "publicKey": "{P256PublicKeyInJWKOrPEMFormat}"
}
{
    "trinsicHpkeVersion": 1,
    "metadata": {
        "mode": 0,
        "kem": 16,
        "kdf": 1,
        "aead": 1,
        "infoHash": "K5iric4zDBxK2mND77jy5Iu9N1K0K+1YXrYMtXbQvJQ=",
        "recipientPublicKeyHash": "mmTQVVYT13zL9eA4HoijLh+FwUzgRC7tV5CaHji+hcI="
    },
    "ephemeralSenderPublicKey": "BMV9NqGWIe00D0Z8z88uN72JC1hR6DaBciSsVDmjGiOLCQLrjRptF1wGrMRpLlmc4m02R4CssDS586eRLItU2yA=",
    "ciphertext": "6/KCzUhwWaAoAioz0z6AU/HbZX8="
}

This API allows you to provide any data to encrypt, a custom infoSuffix, and any P-256 public key string (JWK or PEM).

The output is a TrinsicHPKEBundle, with an HPKE message containing data encrypted against your provided publicKey.

The info used for encryption is in the form:

trinsic-hpke:1:customer-self-test:{infoSuffix}


Decryption Process

Once you have a TrinsicHPKEBundle and your private key on hand, the decryption process should follow these general steps:


1. Validate static metadata

  • Validate HPKE bundle version
    • trinsicHpkeVersion == 1
  • Validate fixed HPKE Parameters
    • metadata.mode == 0
    • metadata.kem == 16
    • metadata.kdf == 1
    • metadata.aead == 1

2. Construct info

You must know the domain and context of the message you are decrypting.

See above for a list of domains and context templates.

  • Determine domain string
  • Create contextString according to domain template
  • Create infoString
    • trinsic-hpke:1:{domain}:{contextString}
  • Encode infoString via UTF-8 encoding to a byte array, infoBytes

3. Perform HPKE

Perform HPKE decryption.

  • Use infoBytes as info
  • Use ephemeralSenderPublicKey as enc
  • Use ciphertext as ct

4. Deserialize Results

The output of HPKE decryption is a byte array dataBytes, which contains a UTF-8 encoded JSON string.

  • Decode dataBytes to a string via UTF-8 to get dataString
  • JSON-deserialize dataString to one of the following models, available in our SDKs:
    • IdentityData
    • GetAttachmentResponse

Did this page help you?