RDF Signify
11. June 2020 (v0.1)
A RDF vocabulary for cryptographic signatures using the ED25519 algorithm.
Table of Contents
1 Introduction
In previous work we have shown how RDF data can be made content-addressable. This automatically allows the integrity of the data to be verified. To ensure authenticity of content we need to mix in some asymmetric cryptography.
We present a simple RDF vocabulary that uses the allows using the Ed25519 algorithm for signing and verifying content. The vocabulary is based on the OpenBSD signify tool and is compatible.
Together with content-addressable RDF this provides robust and easily implementable tools for ensuring authenticity of RDF content.
1.1 Relation to OpenBSD signify
The OpenBSD tool signify
is a major influence for this vocabulary. The cryptographic algorithm used is the same (Ed25519).
The only difference is the encoding of keys and signatures. By switching between encoding of keys and signatures it is possible to use the signify
tool (and other implementations such as minisign) to create and verify keys and signatures.
1.2 Scope
The vocabulary does not provide any mechanisms for key rotation, key revocation or for proving identity of key holder.
2 Vocabulary
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix dcterms: <http://purl.org/dc/terms/> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix voaf: <http://purl.org/vocommons/voaf#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . <> a owl:Ontology ; a voaf:Vocabulary ; dcterms:title "RDF Signify" ; rdfs:label "RDF Signify"; rdfs:comment "A vocabulary for cryptographic signatures using Ed25519."@en .
2.1 Public Key
<#PublicKey> a rdfs:Class ; rdfs:label "Public Key" ; rdfs:comment "An Ed25519 public key" .
Expected properties:
rdf:value
- An Ed25519 public key encoded as
xsd:base64Binary
.
The public key may be published and attached to objects (e.g. an ActivityPub actor) using the <#publicKey>
property:
<#publicKey> a rdfs:Property ; rdfs:range <#PublicKey> ; rdfs:label "Public Key" ; rdfs:comment "An associated Ed25519 public key" .
2.2 Secret Key
<#SecretKey> a rdfs:Class ; rdfs:label "Secret Key" ; rdfs:comment "An Ed25519 secret key" .
Expected properties:
rdf:value
- An Ed25519 secret key encoded as
xsd:base64Binary
.
2.3 Signature
<#Signature> a rdfs:Class ; rdfs:label "Signature" ; rdfs:comment "An Ed25519 signature" . <#message> a rdf:Property ; rdfs:label "Signed Message" ; rdfs:domain <#Signature> .
Expected properties:
<#message>
The message for which the signature was created. Range is either a literal or an IRI.
If message is a literal the Canonical S-Expression
l
form is signed (see Content-Addressable RDF).If message is an IRI then the UTF-8 encoded byte sequence of the IRI is signed.
<#publicKey>
- Reference to the public key that was used to sign message.
rdf:value
- The Ed25519 signature value of the message encoded as
xsd:base64Binary
.
2.4 URN
The vocabulary itself is content-addressed.
From the definitions above we compute a URN using the BLAKE2b cryptographic hash function (see Content-addressable RDF):
urn:blake2b:YJP3KTOL7ZJW5JNIOMTSR4PB4H55ANXKC2AQOBVKSOYEKG5HKNTA
2.5 Note on versioning
The vocabulary does not contain any versioning information. When new cryptographic primitives are required a new vocabulary will be published with a distinct identifier.
3 Example
In the following we will use following example content - an ActivityStreams note that is already content-addressed:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix schema: <https://schema.org/> . @prefix as: <https://www.w3.org/ns/activitystreams> . <urn:blake2b:FBRTEWJUSPW2EDMMITZKWAB5TDBOVT2VOLWWIRUFZFBR72YADB2Q> a as:Note ; as:attributedTo <https://test.example/alice> ; as:content "The clowns just went trough the loop!"@en ; as:image <https://test.example/notes/1#image> ; as:context <https://circus.show/performance-in-funky-town> . <urn:blake2b:FBRTEWJUSPW2EDMMITZKWAB5TDBOVT2VOLWWIRUFZFBR72YADB2Q#image> a as:Image ; as:url <https://test.example/images/1.jpg> .
3.1 Creating a key pair
A key pair can be generated. The public key may be encoded with the signify
vocabulary as follows:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix signify: <urn:blake2b:YJP3KTOL7ZJW5JNIOMTSR4PB4H55ANXKC2AQOBVKSOYEKG5HKNTA> . @prefix dcterms: <http://purl.org/dc/terms/>. <urn:blake2b:MV7FAV6EI7M6RX6LBYS2KDT6GHIV54THO4QBKN7FQKVYB6GTMP5A> a signify:PublicKey ; rdf:value "PSmong1yo6WCrNRi+Qrqfp6XoD5vHeKh31QxptEdDx0="^^xsd:base64Binary ; dcterms:created "2020-06-08"^^xsd:date ; dcterms:description "A public key I created as an example." .
Note that we additionally add some data describing when the key was created and a short description.
The secret key looks like this:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix signify: <urn:blake2b:YJP3KTOL7ZJW5JNIOMTSR4PB4H55ANXKC2AQOBVKSOYEKG5HKNTA> . <urn:blake2b:6FMYHCWYWLTVK34T7HVS7KWE6DQZD7PQTFLM6Y6WBSBDZEJFPLZQ> a signify:SecretKey ; rdf:value "YHSjgbH1p94vUw/6y1Cd618jep3jKNLV1rfK1ur7u0s9KaieDXKjpYKs1GL5Cup+npegPm8d4qHfVDGm0R0PHQ=="^^xsd:base64Binary ; signify:publicKey <urn:blake2b:MV7FAV6EI7M6RX6LBYS2KDT6GHIV54THO4QBKN7FQKVYB6GTMP5A> .
(uri->string (get-base-subject (rdf-fragment-graph-make-content-addressable! (rdf-fragment-graph-add-triples (turtle->rdf "./examples/sec-key-no-iri.ttl" "urn:dummy") (make-rdf-fragment-graph "urn:dummy")))))
The secret key should not be published, it should be kept secret. We have added a reference to the associated public key using the <publicKey>
property, just so that we don’t forget which key this is.
3.2 Signature
The signature looks like this:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix signify: <urn:blake2b:YJP3KTOL7ZJW5JNIOMTSR4PB4H55ANXKC2AQOBVKSOYEKG5HKNTA> . <> a signify:Signature ; signify:message <urn:blake2b:FBRTEWJUSPW2EDMMITZKWAB5TDBOVT2VOLWWIRUFZFBR72YADB2Q> ; rdf:value "13F7cubffmND/8wN+90zWyTiZiEoXWj5D8k61GFswP50ndGG3gLqgkaqwl/ahP/c8UvqXuX3vlTHdXUtXaOBDA=="^^xsd:base64Binary ; signify:publicKey <urn:blake2b:MV7FAV6EI7M6RX6LBYS2KDT6GHIV54THO4QBKN7FQKVYB6GTMP5A> .
Note that the signature is computed only on the IRI urn:blake2b:FBRTEWJUSPW2EDMMITZKWAB5TDBOVT2VOLWWIRUFZFBR72YADB2Q
. Since the IRI is the cryptographic hash of the content we have indirectly signed the content.
The <#publicKey>
property is not necessary but it helps figure out with which pubic key the signature can be verified. If additional context is available it might not be required.
4 Conclusion
We have presented a simple (three classes and two properties) vocabulary that can be used to ensure authenticity of RDF data. Together with content-addressabilty this provides a foundation for building secure and decentralized applications based on RDF while at the same time being compatible with existing RDF tooling and systems.
In further work we intend to explore how this can be used to create a bridge between exising RDF systems such as ActivityPub and completely decentralized systems.
We believe that this is a significantly simpler approach than what is proposed in the context of Linked Data Proofs (Linked Data Signatures), allowing much faster and easier implementation and adoption.
We intend to implement the work presented in the context of the openEngiadina project in order to enable offline-first and decentralized applications.
This work has been supported by the NLNet Foundation trough the NGI0 Discovery Fund.
RDF Signify by openEngiadina is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.