API Specification

Contents:

Whilst there are a range of tools that can automatically query the API, users can also make queries directly to the REST API.

Note

Depending on your geography, you must ensure you use the correct server as detailed in this guide.

The full API specification, written in YAML, is available for users.

There are three main steps for a successful key request:

  1. Determine key request parameters

  2. Perform TLS POST request to the API

  3. Perform local decryption of the output.

Determine key request parameters

Requests are made using JSON, the example below shows a typical JSON structure.

{ 
    'key_type':'AES', 
    'key_parameters': 
     { 
        'size': 256
     }, 
     'nonce':'example1' 
}

For each type of key generated, there are different mandatory and optional parameters available.

Every key request must specify a type (e.g. AES) and a nonce (for security).

The nonce should be a cryptographically random base64-encoded byte-string unique to each request, preferably at least 256-bit (32 bytes) in length.

The key generation matrix specifies all parameters for each key type.

Parameters

Type

Parameter

Required

Format

Meaning

AES

size

Yes

{128, 192, 256}

Number of bits of the AES key

RSA

size

Yes

2048, 3072, 4096

The number of bits of the RSA key

exponent

No

Odd int, >=3

The exponent to use. Default is 65537.

EC

curve

Yes

String

The specific elliptic curve

NTRU-PRIME

variant

Yes

String

The specific key variant

BIKE

variant

Yes

String

The specific key variant

HQC

variant

Yes

String

The specific key variant

SPHINCS+

variant

Yes

String

The specific key variant

KYBER

variant

Yes

String

The specific key variant

DILITHIUM

variant

Yes

String

The specific key variant

FALCON

variant

Yes

String

The specific key variant

CLASSIC-MCELIECE

variant

Yes

String

The specific key variant

Curves and variants

All elliptic curves and post-quantum variants supported can be found in collapsible tables below.

EC curves

Curve

Bits

curve identifier

Brainpool

256

Bp256r1

384

Bp384r1

512

Bp512r1

NIST

192

SecP192r1

224

SecP224r1

256

SecP256r1

384

SecP384r1

521

SecP521r1

Koblitz

192

SecP192k1

224

SecP224k1

256

SecP256k1

Post-quantum algorithm variants

Algorithm

Variant

NTRU-PRIME

NTRULPR-653 NTRULPR-761 NTRULPR-857 NTRULPR-1277 SNTRUP-653 SNTRUP-761 SNTRUP-857 SNTRUP-1277

Kyber

KYBER512 KYBER512-90s KYBER768 KYBER768-90s KYBER1024 KYBER1024-90s

BIKE

BIKE-L1 BIKE-L3

HQC

HQC-128 HQC-192 HQC-256

SPHINCS+

SPHINCS-HARAKA-128F-ROBUST SPHINCS-HARAKA-128F-SIMPLE SPHINCS-HARAKA-128S-ROBUST SPHINCS-HARAKA-128S-SIMPLE SPHINCS-HARAKA-192F-ROBUST SPHINCS-HARAKA-192F-SIMPLE SPHINCS-HARAKA-192S-ROBUST SPHINCS-HARAKA-192S-SIMPLE SPHINCS-HARAKA-256F-ROBUST SPHINCS-HARAKA-256F-SIMPLE SPHINCS-HARAKA-256S-ROBUST SPHINCS-HARAKA-256S-SIMPLE SPHINCS-SHA256-128F-ROBUST SPHINCS-SHA256-128F-SIMPLE SPHINCS-SHA256-128S-ROBUST SPHINCS-SHA256-128S-SIMPLE SPHINCS-SHA256-192F-ROBUST SPHINCS-SHA256-192F-SIMPLE SPHINCS-SHA256-192S-ROBUST SPHINCS-SHA256-192S-SIMPLE SPHINCS-SHA256-256F-ROBUST SPHINCS-SHA256-256F-SIMPLE SPHINCS-SHA256-256S-ROBUST SPHINCS-SHA256-256S-SIMPLE SPHINCS-SHAKE256-128F-ROBUST SPHINCS-SHAKE256-128F-SIMPLE SPHINCS-SHAKE256-128S-ROBUST SPHINCS-SHAKE256-128S-SIMPLE SPHINCS-SHAKE256-192F-ROBUST SPHINCS-SHAKE256-192F-SIMPLE SPHINCS-SHAKE256-192S-ROBUST SPHINCS-SHAKE256-192S-SIMPLE SPHINCS-SHAKE256-256F-ROBUST SPHINCS-SHAKE256-256F-SIMPLE SPHINCS-SHAKE256-256S-ROBUST SPHINCS-SHAKE256-256S-SIMPLE

Dilithium

DILITHIUM2 DILITHIUM3 DILITHIUM5 DILITHIUM2-AES DILITHIUM3-AES DILITHIUM5-AES

Falcon

FALCON-512 FALCON-1024

Classic-McEliece

CLASSIC-MCELIECE-348864 CLASSIC-MCELIECE-348864f CLASSIC-MCELIECE-460896 CLASSIC-MCELIECE-460896f CLASSIC-MCELIECE-6688128 CLASSIC-MCELIECE-6688128f CLASSIC-MCELIECE-6960119 CLASSIC-MCELIECE-6960119f CLASSIC-MCELIECE-8192128f CLASSIC-MCELIECE-8192128f

Performing Local Decryption

This section describes how to decode and decrypt the API response in order to get the newly generated key.

A total of 5 items are required in order to decrypt the response: The sharedSecret from on-boarding, the nonce used in the key request parameters, and the three fields of the API response (counter, encrypted_key, and seed).

API Response

A successful response from the keygen endpoint of the Quantum Origin RESTful API consists of a json payload containing 3 fields:

For example, in the case of AES256:

curl '$QO_URL' \
     --header "Content-Type: application/json" \
     --cert $QO_CERT \
     --key $QO_KEY \
     --data-raw "{'key_type':'AES', 'key_parameters': { 'size': '256' }, 'nonce':'example1' }"

Would produce a result of the following form:

{"counter":0,"encrypted_key":"Nohyo0SeVgv9fO99CNA18LKXsIEyT/ZLaqMms+fyq2v4QmYrquUiebBFrEsOuQ4y","seed":"9vXn02hDStJywPDtHekH+YTOdCfZwMjqpmuJE9tLSh3epLut"}

i.e. (Formatted for readability)

{
  "counter":0,
  "encrypted_key":"Nohyo0SeVgv9fO99CNA18LKXsIEyT/ZLaqMms+fyq2v4QmYrquUiebBFrEsOuQ4y",
  "seed":"9vXn02hDStJywPDtHekH+YTOdCfZwMjqpmuJE9tLSh3epLut"
}

Where:

Field

Description

counter

Integer - initial counter value for the GCM IV

encrypted_key

base64 encoded string containing the ciphertext).

seed

base64 encoded string containing the seed.

Decrypting the New Key

The returned key is encrypted via AES-256 in Gallois/Counter Mode (AES-GCM, see Galois/Counter Mode), under a key constructed from the shared secret and the returned seed value, and using an IV constructed from the seed and counter values, and with additional authenticated data from the nonce value sent in the intial message.

Note that we use a 16 byte GCM tag, and as such the length of resultant key should be exactly 16 bytes less than that of the raw encrypted_key field.

The GCM decryption step will fail if any of the conditions are not met, or if any data field has been tampered with.

Step 1: Gather the data

  1. SharedSecret

Retrieve the SharedSecret that was supplied during the Quantum Origin registration/onboarding process. Decode, if neccessary, into its raw, binary equivalent.

  1. Nonce

Retrieve the nonce value that was used when the keygen request was made. Decode, if neccessary, into its raw, binary equivalent.

  1. Parse the JSON Response

Parse the json response, and decode the two base64 fields into their raw, binary data.

We should now have all of the data required to do the decryption:

Gathered Data

Data Item

Description

SharedSecret

Supplied, typically out-of-band (OOB), during the Quantum Origin registration/onboarding process.

Nonce

The unique nonce value that was used for this specific Keygen request.

encrypted_key

The value should always be >= 16 bytes in length. This is the GCM-encrypted key (of the same length as the request key), appended with a 16 byte “tag”.

seed

The value should always be 36 bytes in length. The first 32 bytes are used in the key derivation function, followed by 4 bytes used as the first 4 byters of the IV.

counter

The value is often zero, but can be any positive unsigned integer.

Step 2 - Key Derivation

As mentioned above, we derive the AES-GCM encryption key from the shared secret and the seed by performing a SHA-256 HMAC. This is similar to an HKDF (see RFC 5869) but skipping the randomness extraction step, as our shared key is already secure and cryptographically random.

To calculate the encryption key, take the first 32 bytes of the seed value returned by the API, and append the byte 0x01; call this data. Then, calculate HMAC-SHA256(SharedSecret, data). This will return the 32 byte key used to encrypt the encrypted_key value.

Step 3 – IV Calculation

We use a 96-bit IV for GCM, following the construction described in NIST SP 800-38D Section 8.2.1. This standard IV construction consists of a 32 bit fixed field, appended with a 64 bit counter value in little-endian format. The 32 bit fixed field is the final four bytes of the seed value returned by the API, and the 64 bit counter is the counter value returned by the API.

To calculate the IV, convert the counter value to a little-endian byte array (i.e. the integer 1 corresponds to the little-endian byte array [0x01, 0x00, {...}, 0x00]), and append it to the last four bytes of the seed.

Note that for the moment, the counter value will always be 0.

Step 4 - Decryption

We now have every input necessary to perform AES-256-GCM decryption:

Data Item

Description

AES-256 key

Derived above

Ciphertext

The encrypted_key, up to but excluding the 16 byte tag.

Authentication Tag

The tag was passed to us as the last 16 bytes of the encrypted_key.

IV

Calculated above

Additional Authenticated Data

The nonce value in the initial request.

Note that some cryptography libraries will implicitly read the authentication tag from the ciphertext and may not need it passed explicitly.