1. Encryption Support
The CBOR library contains support forEncrypting
and Decrypting
arbitrary binary data using a specific scheme called
"CBOR Encryption Format" (CEF).
In similarity to CSF,
CEF also depends on
Deterministic Encoding
which is used to create authentication data to content encryption
algorithms like GCM.
The following is a CEF object (here expressed in CBOR diagnostic notation), using the algorithms
A256GCM
and ECDH-ES+A256KW
for content- respectively key-wrapping:
/ Content encryption algorithm = A256GCM /
1: 3,
/ Key encryption object /
2: {
/ Key encryption algorithm = ECDH-ES+A256KW /
1: -31,
/ Key Id /
3: "example.com:x25519",
/ Ephemeral public key descriptor in COSE format /
7: {
/ kty = OKP /
1: 1,
/ crv = X25519 /
-1: 4,
/ x /
-2: h'c219e35a9c09bfcf1bd6c6dcd1e05ecb36cb6f465d9caeb101795e33fd7db112'
},
/ CipherText (Encrypted key) /
10: h'842916c5c81f8a815ec5ef2a472981b7300bc33fe748928c26e8c4dfff7a4747ecff9caea7040585'
},
/ Tag /
8: h'84ad6926aa92d0de56e4674abf863390',
/ Initialization Vector (IV) /
9: h'c7cc6f77b9f984c15bc3cbeb',
/ Ciphertext (Encrypted Content) /
10: h'625c2b2a41907547b2210624e1e818991c00790aed16'
}
The same object expressed as hex-encoded CBOR:
Decryption of this object using the private key (here in JWK format)
"kid": "example.com:x25519",
"kty": "OKP",
"crv": "X25519",
"x": "6ZoM7yBYlJYNmxwFl4UT3MtCoTv7ztUjpRuKEXrV8Aw",
"d": "cxfl86EVmcqrR07mWENCf1F_5Ni5mt1ViGyERB6Q1vA"
}
"Hello encrypted world!"
.
2. Encryption Container
The following figure shows the layout of CEF objects:
2.1. Content Encryption Map
The following table shows the function and type of each element of content encryption maps:Name | Label | Argument | Description |
---|---|---|---|
customData | 0 |
"Any" | Optional: data included (in clear) in the CEF container. Also see Crypto Options. |
algorithm | 1 |
int | Content encryption algorithm using COSE identifiers. |
keyEncryption | 2 |
map |
Optional: Key encryption parameters. |
keyId | 3 |
"Any" | Optional: key identifier using any valid CBOR object.
Note that keyId must not be used together with the
keyEncryption option.
A compliant keyId
must uniquely identify a specific signature key. |
tag | 8 |
bstr |
Authentication Tag. |
iv | 9 |
bstr | Initialization Vector (IV). |
cipherText | 10 |
bstr | Encrypted content. |
2.2. Key Encryption Map
The following table shows the function and type of each element of key encryption maps:Name | Label | Argument | Description |
---|---|---|---|
algorithm | 1 |
int | Key encryption algorithm using COSE identifiers. |
keyId | 3 |
"Any" | Optional: key identifier using
any valid CBOR object.
Note that keyId must not be used together with
publicKey or certificatePath .
A compliant keyId must uniquely identify a specific key encryption key.
|
publicKey | 4 |
map |
Optional: public key in COSE format. Note that public key objects must not contain additional information like key identifiers or preferred algorithms. |
certificatePath | 5 |
array | Optional: certificate path supplied
as an array of byte string objects holding X.509 certificates in DER format,
where the first object must be the encryption certificate.
Key encryption objects must not contain both certificatePath
and publicKey elements.
|
ephemeralKey | 7 |
map |
Optional: public key in COSE format. Used by ECDH algorithms. |
cipherText | 10 |
bstr |
Optional: Encrypted key. Used by key-wrapping algorithms. |
3. Decryption Process
This section describes the steps needed to decrypt a CEF object (encryption is performed by reversing the process by generating and writing data).
Begin by defining the variables
contentEncryptionAlgorithm
,
contentEncryptionKey
, and
additionalAuthenticationData
.
3.1 Get Content Encryption Algorithm
Perform the following steps:- Decode the Content Encryption Map.
- Set
contentEncryptionAlgorithm =
algorithm
.
3.2 Recover Content Encryption Key
For key encryption schemes (= having akeyEncryption
attribute), perform the following steps:
- Decode the Key Encryption Map.
- Determine the
privateKey
to use. Private keys are either implicit, or are identified through akeyId
,publicKey
, orcertificatePath
attribute. - Recover the
contentEncryptionKey
by applying thealgorithm
,ephemeralKey
,cipherText
, and the previously locatedprivateKey
to an associated key decryption method, while using thecontentEncryptionAlgorithm
to get the expected length of the key.
contentEncryptionKey
is
either implicit or is located through a keyId
attribute.
3.3. Decrypt Content
Finalize the decryption process by performing the following steps:
- Read and save the
tag
,iv
, andciphertext
attributes from the Content Encryption Map. - Remove the
tag
,iv
, andciphertext
attributes from the Content Encryption Map. Note that the top levelmap
object must be updated as well to reflect the changed number of elements. - Serialize the remaining CBOR object
(including the optional Key Encryption Map),
and assign the result to the
additionalAuthenticationData
(AAD
) variable. - Apply the
contentEncryptionAlgorithm
(in decrypt mode) to the recoveredcontentEncryptionKey
, the attributes read in the step #1, and theadditionalAuthenticationData
.
4. Algorithms
4.1. Key Derivation Function (KDF)
ECDH based key encryption schemes must use a Key Derivation Function (KDF) according to HKDF [RFC 5869], profiled as follows:hmac
: The HKDF implementation must use HMAC with SHA-256salt
: N/A. The default extract mode handling must be implemented.info
: This parameter must consist of the actual COSE key encryption algorithm, expressed as a 32-bit (4 byte) signed big-endian integer.
4.2. Content Encryption Algorithms
Name | Identifier | Compatibility |
---|---|---|
A128GCM | 1 | COSE, JOSE |
A192GCM | 2 | COSE, JOSE |
A256GCM | 3 | COSE, JOSE |
A128CBC-HS256 | 200 | JOSE |
A192CBC-HS384 | 201 | JOSE |
A256CBC-HS512 | 202 | JOSE |
4.3. Key Encryption Algorithms
Name | Identifier | Compatibility | Notes |
---|---|---|---|
ECDH-ES | -25 | COSE, JOSE | 1, 2 |
ECDH-ES+A128KW | -29 | COSE, JOSE | 1, 2 |
ECDH-ES+A192KW | -30 | COSE, JOSE | 1, 2 |
ECDH-ES+A256KW | -31 | COSE, JOSE | 1, 2 |
RSA-OAEP | -40 | COSE, JOSE | 3 |
RSA-OAEP-256 | -41 | COSE, JOSE | 3 |
- CEF and COSE use different profiles for the Key Derivation Function (KDF).
- Supported key types:
P-256
,P-384
,P-521
,X25519
, andX448
. - Supported key lengths:
2048
,3072
, and4096
5. Tagged and Custom Encryption Data
The CEF container can be enhanced through a couple of options described in Crypto Options. Such options are included in the data to be authenticated.6. Test Vectors
An extensive set of test vectors is currently available at: https://github.com/cyberphone/openkeystore/tree/master/testdata/cbor-encryption .
Use CBORPrinter
to list contents in a human-friendly way.
7. Using the Encryption API
The following section outlines how the encryption API is supposed to be used.Sample program:
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.webpki.cbor.CBORAsymKeyDecrypter;
import org.webpki.cbor.CBORAsymKeyEncrypter;
import org.webpki.cbor.CBORKeyPair;
import org.webpki.cbor.CBORDecoder;
import org.webpki.crypto.ContentEncryptionAlgorithms;
import org.webpki.crypto.KeyEncryptionAlgorithms;
import org.webpki.util.HexaDecimal;
import org.webpki.util.UTF8;
public class EncryptionDemo {
// Message encoded in UTF-8.
static final byte[] SECRET_MESSAGE = UTF8.encode("A very secret message");
// X25519 private key in COSE format.
static final byte[] X25519_PRIVATE_KEY = HexaDecimal.decode(
"a401012004215820e99a0cef205894960d9b1c05978513dccb" +
"42a13bfbced523a51b8a117ad5f00c2358207317e5f3a11599" +
"caab474ee65843427f517fe4d8b99add55886c84441e90d6f0");
public static void main(String[] args) {
// Get keys in Java format.
KeyPair keyPair = CBORKeyPair.convert(CBORDecoder.decode(X25519_PRIVATE_KEY));
PrivateKey receiverKey = keyPair.getPrivate();
PublicKey senderKey = keyPair.getPublic();
// Encrypt data using CEF.
byte[] encryptionObject = new CBORAsymKeyEncrypter(senderKey,
KeyEncryptionAlgorithms.ECDH_ES,
ContentEncryptionAlgorithms.A256GCM)
.encrypt(SECRET_MESSAGE).encode();
// Decrypt data using CEF.
byte[] decryptedData = new CBORAsymKeyDecrypter(receiverKey)
.decrypt(CBORDecoder.decode(encryptionObject));
// Assume that the data is a string encoded in UTF-8.
String secretMessage = UTF8.decode(decryptedData);
System.out.println(secretMessage);
}
}
Sample key in diagnostic notation:
1: 1,
-1: 4,
-2: h'e99a0cef205894960d9b1c05978513dccb42a13bfbced523a51b8a117ad5f00c',
-4: h'7317e5f3a11599caab474ee65843427f517fe4d8b99add55886c84441e90d6f0'
}
The resulting encryption object in diagnostic notation:
1: 3,
2: {
1: -25,
7: {
1: 1,
-1: 4,
-2: h'3e9c03b4e2ccb023272fe0f1a5a414645a7e5a0952a3da8199ba46812603ee1a'
}
},
8: h'4ac80be51285309b93b8f4cc38f6b8ba',
9: h'9fbd6e151bad2af177dd3382',
10: h'115b48dcffcf88dce70b2173d6c368b2cfe802521c'
}
The resulting encryption object expressed in hexadecimal: