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:
Determine key request parameters
Perform TLS POST request to the API
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 |
---|---|---|---|---|
|
||||
|
Yes |
{128, 192, 256} |
Number of bits of the AES key |
|
|
||||
|
Yes |
2048, 3072, 4096 |
The number of bits of the RSA key |
|
|
No |
Odd int, >=3 |
The exponent to use. Default is 65537. |
|
|
||||
|
Yes |
String |
The specific elliptic curve |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key variant |
|
|
||||
|
Yes |
String |
The specific key 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 |
|
---|---|---|
Brainpool |
256 |
|
384 |
|
|
512 |
|
|
NIST |
192 |
|
224 |
|
|
256 |
|
|
384 |
|
|
521 |
|
|
Koblitz |
192 |
|
224 |
|
|
256 |
|
Post-quantum algorithm variants
Algorithm |
Variant |
---|---|
NTRU-PRIME |
|
Kyber |
|
BIKE |
|
HQC |
|
SPHINCS+ |
|
Dilithium |
|
Falcon |
|
Classic-McEliece |
|
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
SharedSecret
Retrieve the SharedSecret that was supplied during the Quantum Origin registration/onboarding process. Decode, if neccessary, into its raw, binary equivalent.
Nonce
Retrieve the nonce value that was used when the keygen request was made. Decode, if neccessary, into its raw, binary equivalent.
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:
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.