This document shows the manual creation of all resources.
These examples are generated manually using the following command line tools:
- OpenSSL: Core cryptography functionality.
- pipetransform: Transform streams to different encodings.
Long streams of characters are truncated in the middle
using ...
, to improve readability.
If you want to read the files referenced in these examples, they are all available here.
Table of Contents
- Commands: Command line commands used in these examples
- Create User Identity: Create an SDMP user identity
- Create Node Identity: Create an SDMP node identity
- Create Trust: Authorize that node on behalf of the user
- Start Journal: Start a journal for that node
- Publish "Public" Resource: Publish a resource with contents visible to all nodes
- Publish "Private" Resource: Publish a resource with contents encrypted to a user/node
Commands
The following commands are used in this example:
Generate a private and public key:
openssl genrsa -out private.pem 2056
openssl rsa -in private.pem -pubout -out public.pem
Make the public key formatted for the SDMP:
cat public.pem | keytransform remove > public.sdmp
Encrypt/decrypt a file using a public RSA key:
openssl rsautl -encrypt -pubin -inkey public.pem -in aes256.key -out aes256.enc
openssl rsautl -decrypt -inkey private.pem -in aes256.enc
Sign/verify some file using the SHA512 hash and RSA keys:
openssl dgst -sha512 -sign private.pem -out file.txt.sha file.txt
openssl dgst -sha512 -verify public.pem -signature file.txt.sha file.txt
Generate AES keys or IV values:
openssl rand 32 > aes256.key
openssl rand 16 > iv.key
Encrypt/decrypt using AES CBC:
openssl enc -aes-256-cbc -salt -in file.txt -out file.enc -K $KEY$ -iv $IV$
openssl enc -d -aes-256-cbc -in file.enc -K $KEY$ -iv $IV$
(Note: The values $KEY$
and $IV$
must be valid hex encoded key
and initialization vector values.)
Encode files to some other encoding (e.g. hex):
cat iv.key | pipetransform binary hex
Generate the SHA512 hash for some file:
openssl dgst -sha512 file.txt
Alternate method which also encodes to base64url:
cat file.txt | openssl dgst -sha512 -binary | pipetransform binary base64url
Creating a User Identity
Generating compliant keys using OpenSSL is done with the command:
openssl genrsa -out private.pem 2056
Generating the public key is done with the command:
openssl rsa -in private.pem -pubout -out public.pem
And turning those keys into SDMP formatted keys is done with the command:
cat public.pem | keytransform remove > public.sdmp
We'll start by creating a private/public key and identity for a user named Bob.
openssl genrsa -out bob-private.pem 2056
openssl rsa -in bob-private.pem -pubout -out bob-public.pem
cat bob-public.pem | keytransform remove > bob-public.sdmp
These files are available here:
A complete identity container looks like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "identity" ]
},
"identity": {
"type": "user",
"expires": "2020-01-01T00:00:00.000Z",
"key": "$PUBLIC_KEY$"
}
}
Bob's formatted public key (bob-public.sdmp
) looks like:
MIIBIzANBgkqhki...MMZ1cLakCAwEAAQ==
So the identity container would look like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "identity" ]
},
"identity": {
"type": "user",
"expires": "2020-01-01T00:00:00.000Z",
"key": "MIIBIzANBgkqhki...MMZ1cLakCAwEAAQ=="
}
}
The complete identity container is available here:
To publish the identity, it must first be placed inside a signature object, which looks like:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "signature" ]
},
"signature": {
"identifier": "$IDENTIFIER$",
"payload": "$PAYLOAD$",
"signatures": [{
"protected": "$PROTECTED_HEADER$",
"signature": "$SIGNATURE$"
}]
}
}
The signature.identifier
property (which is also the
resource identifier)
is generated by hashing the payload, which is the
bob-identity.json
file. This is done using the
OpenSSL command:
openssl dgst -sha512 -binary bob-identity.json | pipetransform binary base64url
Which outputs the value (used as the signature.identifier
):
5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
The payload is the identity JSON object, encoded to base64url. To do this, we can use the pipetransform tool:
cat bob-identity.json | pipetransform utf8 base64url > bob-identity.encoded
Which outputs the following (truncated with ellipsis for
readability), used as the signature.payload
property:
eyJzZG1wIjp7InZl...DQXdFQUFRPT0ifX0
The encoded payload is available here:
The protected
property is the base64url encoded JSON object:
{
"alg": "HS512",
"kid": "$KEY_FINGERPRINT$"
}
The kid
value (the key fingerprint)
is the hash of the identity.key
value. This is generated using the command:
openssl dgst -sha512 -binary bob-public.sdmp | pipetransform binary base64url
Which outputs the key fingerprint (used as the kid
property):
1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A
Which means that the JSON object would be:
{
"alg": "HS512",
"kid": "1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A"
}
The JSON header is available here:
The protected header is generated by encoding this JSON header as base64url:
cat bob-identity-protected.json | pipetransform utf8 base64url > bob-identity-protected.encoded
Which outputs the value:
eyJhbGciOiJIUzUx...mRFZNX3ktbzdBIn0
The complete value is available here:
The signature
property is the signature of the payload, and is
generated using the following command:
openssl dgst -sha512 -sign bob-private.pem bob-identity.encoded | pipetransform binary base64url > bob-identity-signature.encoded
Which outputs the value:
cp1okHSfgQWajNp9...M76pYlMG8qp8Q4xk
The complete value is available here:
Finally, the assembled signature object would look like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "signature" ]
},
"signature": {
"identifier": "5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A",
"payload": "eyJzZG1wIjp7InZl...DQXdFQUFRPT0ifX0",
"signatures": [{
"protected": "eyJhbGciOiJIUzUx...mRFZNX3ktbzdBIn0",
"signature": "cp1okHSfgQWajNp9...M76pYlMG8qp8Q4xk"
}]
}
}
The full signature object is available here:
This file is the user identity resource.
The important parts are:
- The key fingerprint of the user is:
1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A
- The resource identifier is:
5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
Creating a Node Identity
The same process is followed to create a node
identity, except
that the node identity container
looks like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "identity" ]
},
"identity": {
"type": "node",
"expires": "2020-01-01T00:00:00.000Z",
"key": "$PUBLIC_KEY$"
}
}
Using the above steps, we generate the following files:
- node-private.pem
- node-public.pem
- node-public.sdmp
- node-identity.json
- node-identity.encoded
- node-identity-protected.json
- node-identity-protected.encoded
- node-identity-signature.json
And the important parts are:
- The key fingerprint of the node is:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
- The resource identifier is:
6ECGQ9anD4milwgB-tixENh6_SHpVtzsgdL9vqZ85_XOgXG525poxQlpH1WIuJg7jbS0nwPgie-xiMM9U9PFqA
Create a Trust
In order for the node to publish resources on behalf of the user, the user must create a trust authorizing the node.
Assuming that the user is giving the node normal read/write access, the trust container would look like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "trust" ]
},
"trust": {
"trustee": "IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw",
"expires": "2020-01-01T00:00:00.000Z",
"authorization": [
"read_encrypted",
"publish_resource",
"revoke"
]
}
}
This container is available here:
The user must then generate a resource with this container.
The SHA512 of the trust container is:
GpUTDufRSi-nLwCX7kjmFbn-_xO7m-XtNG7FVFtwBk4vl8oE8e4jJzMs_eDlvrZ0mQqeZ8B1he9BaLYGlAvdUQ
Note that the protected
property of the resource signatures
object is the same for the user, since it is the same key
identifier. The protected
property is available here:
And the signature property is available here:
Which makes the resource object this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "signature" ]
},
"resource": {
"user":
},
"signature": {
"identifier": "GpUTDufRSi-nLwCX7kjmFbn-_xO7m-XtNG7FVFtwBk4vl8oE8e4jJzMs_eDlvrZ0mQqeZ8B1he9BaLYGlAvdUQ",
"payload": "eyJzZG1wIjp7InZl...LCJyZXZva2UiXX19",
"signatures": [{
"protected": "eyJhbGciOiJIUzUx...mRFZNX3ktbzdBIn0",
"signature": "vxjZrnb1kklSfcsE...CH1P-7qk77TmtdPU"
}]
}
}
This resource is available here:
Starting a Journal
Each node maintains a journal. For this example we will use a flat text file to store the journal entries.
The node initializes the journal to be exactly this:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
(See the node journal at step 1 here.)
The second entry is the identity resource of the user authorizing the node. The properties of the second entry are:
- Line identifier:
2YLFjtSFIFYviDLjt8PbLsrRApuYZCk2mgnT8t07AidsuOODTZMUP5hL7iQKeNxJ8uwlEygLCmiEuXOFyJliQw
- Key fingerprint:
1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A
- Resource identifier:
5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
Which makes the journal to be exactly this:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
2YLFjtSFIFYviDLjt8PbLsrRApuYZCk2mgnT8t07AidsuOODTZMUP5hL7iQKeNxJ8uwlEygLCmiEuXOFyJliQw@1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A/5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
(See the node journal at step 2 here.)
The third entry is the trust resource we created earlier. The properties of this entry are:
- Line identifier:
7lly-uncz6Y1QP8JJSlYJKUchKnsAYXaWqUVbY1x3SVcmgpiJM1UdnWAC9XazSzbMSGsYjsIS-NlRblIXplsXQ
- Key fingerprint:
1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A
- Resource identifier:
GpUTDufRSi-nLwCX7kjmFbn-_xO7m-XtNG7FVFtwBk4vl8oE8e4jJzMs_eDlvrZ0mQqeZ8B1he9BaLYGlAvdUQ
Which makes the journal to be exactly this:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
2YLFjtSFIFYviDLjt8PbLsrRApuYZCk2mgnT8t07AidsuOODTZMUP5hL7iQKeNxJ8uwlEygLCmiEuXOFyJliQw@1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A/5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
7lly-uncz6Y1QP8JJSlYJKUchKnsAYXaWqUVbY1x3SVcmgpiJM1UdnWAC9XazSzbMSGsYjsIS-NlRblIXplsXQ@1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A/GpUTDufRSi-nLwCX7kjmFbn-_xO7m-XtNG7FVFtwBk4vl8oE8e4jJzMs_eDlvrZ0mQqeZ8B1he9BaLYGlAvdUQ
(See the node journal at step 3 here.)
Publish "Public" Resource
Suppose now that the user wishes to publish a resource using the node. We will use a node resource, to publish additional information about the user, and we won't encrypt it to a specific user.
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "user" ]
},
"user": {
"name": "Bob Smith",
"about": "Works for the man."
}
}
This file is available here:
The protected
header of the resource object will be different
than previously, because it will be generated using the key
fingerprint of the node instead of the user:
{
"alg": "HS512",
"kid": "IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw"
}
These files are available here:
Together, this makes the resource look like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "signature" ]
},
"resource": {
"user": "IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw"
},
"signature": {
"identifier": "aXGppFC6WWoSwx61Fs0bAHLij38_AWVRNDupbUC1sQti9ToT1VKs_zoxoMG-Gb66OHVcwIOdKooRYLPn_4-J9g",
"payload": "eyJzZG1wIjp7InZl...IHRoZSBtYW4uIn19",
"signatures": [{
"protected": "eyJhbGciOiJIUzUx...0R0JuYWx5UFl3In0",
"signature": "BJePo0l_-mitxKy9...b69_Sqpd7P9brbK4"
}]
}
}
This complete file is available here:
Publishing this entry to the node's journal gives the following properties:
- Line identifier:
FTwNvVSwKrW16wFBKgEsRiyfgrysoR4mJtJBC1hECfWTonQ0lHoaavJHJUdUEsWyc9t5bgq3rFNwiaUjK3jDiw
- Key fingerprint:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
- Resource identifier:
aXGppFC6WWoSwx61Fs0bAHLij38_AWVRNDupbUC1sQti9ToT1VKs_zoxoMG-Gb66OHVcwIOdKooRYLPn_4-J9g
Which makes the journal to be exactly this:
IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw
2YLFjtSFIFYviDLjt8PbLsrRApuYZCk2mgnT8t07AidsuOODTZMUP5hL7iQKeNxJ8uwlEygLCmiEuXOFyJliQw@1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A/5w4IzlVU2d6KxWFhNF2hUW-rECxS6Kbi4PJ2B2z0-6n243MfYr0iPlF06S35Usd_zMPemVmPcI2WrifStdlN4A
7lly-uncz6Y1QP8JJSlYJKUchKnsAYXaWqUVbY1x3SVcmgpiJM1UdnWAC9XazSzbMSGsYjsIS-NlRblIXplsXQ@1Zy3eUBJAAYwfvfmO8uOYFKHY54fIz_jkOzBddcTb-IXlhos_LJcMlMafHABimG0_afp_gc9fNEcfDVM_y-o7A/GpUTDufRSi-nLwCX7kjmFbn-_xO7m-XtNG7FVFtwBk4vl8oE8e4jJzMs_eDlvrZ0mQqeZ8B1he9BaLYGlAvdUQ
FTwNvVSwKrW16wFBKgEsRiyfgrysoR4mJtJBC1hECfWTonQ0lHoaavJHJUdUEsWyc9t5bgq3rFNwiaUjK3jDiw@IMJ--MJJMtV9PVsR82vKWaJaj7P0TB6tJVB9i5aAcQzuy6I6x4S3tDLHN6lJ2_m6U_bo9SClnsqotGBnalyPYw/aXGppFC6WWoSwx61Fs0bAHLij38_AWVRNDupbUC1sQti9ToT1VKs_zoxoMG-Gb66OHVcwIOdKooRYLPn_4-J9g
(See the node journal at this step here.)
Publish "Private" Resource
Suppose now that the user wishes to publish a resource using the node. We will publish a node resource, to publish additional information about the node, and we will encrypt it to a specific user.
The final object will be the result of this pseudo-function:
RESOURCE(SIGN(ENCRYPT(Node Schema Object)))
Suppose that we have previously obtained and verified the public key of Alice:
openssl genrsa -out alice-private.pem 2056
openssl rsa -in alice-private.pem -pubout -out alice-public.pem
And suppose that we have also previously obtained and verified
the public key of a node. Also assume that we have previously
verified that Alice has published a trust
giving this node read_encrypted
authorization:
openssl genrsa -out alice-node-private.pem 2056
openssl rsa -in alice-node-private.pem -pubout -out alice-node-public.pem
These files are available here:
The encrypted payload must be a container, so we first generate the node resource like so:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "node" ]
},
"information": {
"type": "node",
"name": "Bob's Laptop",
"ips": [
"123.456.789.012:34567",
"[2001:db8:85a3:0:0:8a2e:370:7334]:50123"
]
}
}
This file is available here:
The encrypted container is the container which
we will publish. Since we are sending a private message to Alice,
we must encrypt the message to Alice's key and to the key of the
node given read_encrypted
authorization. Therefore, the container
looks like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "encrypted" ]
},
"encrypted": {
"protected": "$PROTECTED_HEADERS$",
"iv": "$INITIALIZATION_VECTOR$",
"payload": "$PAYLOAD$",
"recipients": [{
"key": "$KEY_ALICE$"
},{
"key": "$KEY_ALICE_NODE$"
}]
}
}
First we need to generate a shared AES key and an initialization vector:
openssl rand 32 > resource-node-aes256.key
openssl rand 16 > resource-node-iv.key
These files are available here:
We can convert it to hexadecimal for use with the OpenSSL command line using the pipetransform command:
cat resource-node-aes256.key | pipetransform binary hex
cat resource-node-iv.key | pipetransform binary hex
Which output the following hex values:
4040c2bcfedcf3ac6f4e5294c10da29bbed91f6b37c205bb90ddbf4aa8485b6c
d0ee0ccf1ce1969b37d6db6d3b8e4345
We can then encrypt the JSON file using this key:
openssl enc -aes-256-cbc -salt -in resource-node.json -out resource-node.json.encrypted -K 4040c2bcfedcf3ac6f4e5294c10da29bbed91f6b37c205bb90ddbf4aa8485b6c -iv d0ee0ccf1ce1969b37d6db6d3b8e4345
This encrypted file is available here:
The encrypted.payload
property must be stored in base64url encoding,
therefore we encode the encrypted file:
cat resource-node.json.encrypted | pipetransform binary base64url > resource-node.json.encrypted.encoded
Which outputs the following:
pgo30jyrPCyMK09M...XexJt8w6TF0BnueU
This value is available in the file:
The encrypted.iv
property must also be stored in base64url encoding,
therefore:
cat resource-node-iv.key | pipetransform binary base64url
Which outputs the following:
0O4Mzxzhlps31tttO45DRQ
We need to encrypt the shared key to the two public keys. This is done using the OpenSSL commands:
openssl rsautl -encrypt -pubin -inkey alice-public.pem -in resource-node-aes256.key -out resource-node-aes256-alice.key.encrypted
openssl rsautl -encrypt -pubin -inkey alice-node-public.pem -in resource-node-aes256.key -out resource-node-aes256-node.key.encrypted
And these encrypted values must be base64url encoded:
cat resource-node-aes256-alice.key.encrypted | pipetransform binary base64url > resource-node-aes256-alice.key.encrypted.encoded
cat resource-node-aes256-node.key.encrypted | pipetransform binary base64url > resource-node-aes256-node.key.encrypted.encoded
The output of these looks like:
- Encrypted for Alice:
HwbM20QZipPO4-cv...QGs6qQnklxcyQmXg
- Encrypted for Alice's node:
QxC8ipIofCKWVNAd...MWUCz6ZInW6jADYY
These files are available here:
- resource-node-aes256-alice.key.encrypted
- resource-node-aes256-node.key.encrypted
- resource-node-aes256-alice.key.encrypted.encoded
- resource-node-aes256-node.key.encrypted.encoded
This means the final encrypted container will look like this:
{
"sdmp": {
"version": "0.11.0",
"schemas": [ "encrypted" ]
},
"encrypted": {
"protected": "$PROTECTED_HEADERS$",
"iv": "0O4Mzxzhlps31tttO45DRQ",
"payload": "pgo30jyrPCyMK09M...XexJt8w6TF0BnueU",
"recipients": [{
"key": "HwbM20QZipPO4-cv...QGs6qQnklxcyQmXg"
},{
"key": "QxC8ipIofCKWVNAd...MWUCz6ZInW6jADYY"
}]
}
}
The full file is available here:
The rest of the process is the same as the
"Publish Public Resource" section,
except that the file resource-node-encrypted.json
is the payload.