Commit 286c5a13bb466f90d3f96a763984132a5e818755
add protocol guides
Paul Frazee committed on 3/17/2016, 12:32:12 AMParent: 254c89b83aef67583e5b1b6f6cd5fdba4fb0b493
Files changed
tmpl/docs/advanced/links.md | ||
---|---|---|
@@ -1,5 +1,5 @@ | ||
1 | -# Content-Hash Linking | |
1 | +## Content-Hash Linking | |
2 | 2 | |
3 | 3 | Messages, feeds, and blobs are addressable by specially-formatted identifiers. |
4 | 4 | Message and blob IDs are content-hashes, while feed IDs are public keys. |
5 | 5 |
tmpl/docs/advanced/advanced-queries.md | ||
---|---|---|
@@ -1,19 +1,0 @@ | ||
1 | -## About-user messages | |
2 | - | |
3 | -```js | |
4 | -var pull = require('pull-stream') | |
5 | -pull( | |
6 | - sbot.links({ dest: userId, rel: 'about', values: true }), | |
7 | - pull.collect(function (err, msgs) { ... }) | |
8 | -) | |
9 | -``` | |
10 | -```bash | |
11 | -sbot links --dest {userId} --rel about --values | |
12 | -``` | |
13 | - | |
14 | -[About messages](/docs/message-types/about.html) put their name & image attributes outside of the link, so we need `links` to fetch the full message-value. | |
15 | -That's why `values: true` is set. | |
16 | - | |
17 | -[→ links API](/apis/scuttlebot/ssb.html#links-source) | |
18 | - | |
19 | - |
tmpl/guides/concepts/private-box.html.js | ||
---|---|---|
@@ -1,190 +1,0 @@ | ||
1 | -var page = require('../../page.part') | |
2 | -var com = require('../../com.part') | |
3 | - | |
4 | -module.exports = () => page({ | |
5 | - section: 'guides', | |
6 | - tab: 'guides-concepts', | |
7 | - path: '/protocols/private-box.html', | |
8 | - content: ` | |
9 | - <h2>Private Box</h2> | |
10 | - <p> | |
11 | - Private-box is a format for encrypting a private message to many parties. | |
12 | - You can <strong><a href="https://github.com/auditdrivencrypto/private-box">find the repository on GitHub</a></strong>. | |
13 | - </p> | |
14 | - | |
15 | - <h2 id="properties">Properties</h2> | |
16 | - <p> | |
17 | - This protocol was designed for use with secure-scuttlebutt. | |
18 | - In this place, messages are placed in public, and the sender is known via a signature, | |
19 | - but we can hide the recipient and the content. | |
20 | - </p> | |
21 | - | |
22 | - <h4 id="-recipients-are-hidden-">Recipients are hidden.</h4> | |
23 | - <p> | |
24 | - An eaves-dropper cannot know the recipients or their number. | |
25 | - Since the message is encrypted to each recipient, and then placed in public, | |
26 | - to receive a message you will have to decrypt every message posted. | |
27 | - This would not be scalable if you had to decrypt every message on the internet, | |
28 | - but if you can restrict the number of messages you might have to decrypt, | |
29 | - then it's reasonable. For example, if you frequented a forum which contained these messages, | |
30 | - then it would only be a reasonable number of messages, and posting a message would only | |
31 | - reveal that you where talking to some other member of that forum. | |
32 | - </p> | |
33 | - <p>Hiding access to such a forum is another problem that's out of the current scope.</p> | |
34 | - | |
35 | - <h4 id="-the-number-of-recipients-are-hidden-">The number of recipients are hidden.</h4> | |
36 | - <p> | |
37 | - If the number of recipients was not hidden, then sometimes it would be possible | |
38 | - to deanonymise the recipients, if there was a large group discussion with | |
39 | - an unusual number of recipients. Encrypting the number of recipients means that, | |
40 | - when a message is not encrypted to you, you will attempt to decrypt same number of times | |
41 | - as the maximum recipients. | |
42 | - </p> | |
43 | - | |
44 | - <h4 id="-a-valid-recipient-does-not-know-the-other-recipients-">A valid recipient does not know the other recipients.</h4> | |
45 | - <p> | |
46 | - A valid recipient knows the number of recipients but now who they are. | |
47 | - This is more a sideeffect of the design than an intentional design element. | |
48 | - The plaintext contents may reveal the recipients, if needed. | |
49 | - </p> | |
50 | - | |
51 | - <h4 id="-by-providing-the-key-for-a-message-an-outside-party-could-decrypt-the-message-">By providing the key for a message, an outside party could decrypt the message.</h4> | |
52 | - <p> | |
53 | - When you tell someone a secret you must trust them not to reveal it. | |
54 | - Anyone who knows the key could reveal that to some other party who could then read the message content, | |
55 | - but not the recipients (unless the sender revealed the ephemeral secret key). | |
56 | - </p> | |
57 | - | |
58 | - <h2 id="assumptions">Assumptions</h2> | |
59 | - <p> | |
60 | - Messages will be posted in public, so that the sender is likely to be known, | |
61 | - and everyone can read the messages. (This makes it possible to hide the recipient, | |
62 | - but probably not the sender.) | |
63 | - </p> | |
64 | - <p>Resisting traffic analysis of the timing or size of messages is out of scope of this spec.</p> | |
65 | - | |
66 | - <h2 id="prior-art">Prior Art</h2> | |
67 | - <h4 id="-pgp-">PGP</h4> | |
68 | - <p> | |
69 | - In PGP the recipient, the sender, and the subject are sent as plaintext. | |
70 | - If the recipient is known, then the metadata graph of who is communicating with who can be read, | |
71 | - which, since it is easier to analyze than the content, is important to protect. | |
72 | - </p> | |
73 | - <h4 id="-sodium-seal-">Sodium seal</h4> | |
74 | - <p> | |
75 | - The Sodium library provides a <em>seal</em> function that generates an ephemeral keypair, | |
76 | - derives a shared key to encrypt a message, and then sends the ephemeral public key and the message. | |
77 | - The recipient is hidden, and it is forward secure if the sender throws out the ephemeral key. | |
78 | - However, it's only possible to have one recipient. | |
79 | - </p> | |
80 | - | |
81 | - <h4 id="-minilock-">Minilock</h4> | |
82 | - <p> | |
83 | - Minilock uses a similar approach to <code>private-box</code> but does not hide the | |
84 | - number of recipients. In the case of a group discussion where multiple rounds | |
85 | - of messages are sent to everyone, this may enable an eavesdropper to deanonymize | |
86 | - the participiants of a discussion if the sender of each message is known. | |
87 | - </p> | |
88 | - | |
89 | - <h2 id="api">API</h2> | |
90 | - | |
91 | - <h4 id="-encrypt-plaintext-buffer-recipients-array-curve25519_pk-">encrypt (plaintext Buffer, recipients Array<curve25519_pk>)</h4> | |
92 | - <p> | |
93 | - Takes a plaintext buffer of the message you want to encrypt, | |
94 | - and an array of recipient public keys. | |
95 | - Returns a message that is encrypted to all recipients | |
96 | - and openable by them with <code>PrivateBox.decrypt</code>. | |
97 | - The recipients must be between 1 and 7 items long. | |
98 | - </p> | |
99 | - <p> | |
100 | - The encrypted length will be <code>56 + (recipients.length * 33) + plaintext.length</code> bytes long, | |
101 | - between 89 and 287 bytes longer than the plaintext. | |
102 | - </p> | |
103 | - | |
104 | - <h4 id="-decrypt-cyphertext-buffer-secretkey-curve25519_sk-">decrypt (cyphertext Buffer, secretKey curve25519_sk)</h4> | |
105 | - <p> | |
106 | - Attempt to decrypt a private-box message, using your secret key. | |
107 | - If you where an intended recipient then the plaintext will be returned. | |
108 | - If it was not for you, then <code>undefined</code> will be returned. | |
109 | - </p> | |
110 | - | |
111 | - <h2 id="protocol">Protocol</h2> | |
112 | - <h4 id="-encryption-">Encryption</h4> | |
113 | - <p>Private-box generates:</p> | |
114 | - <ul> | |
115 | - <li><code>ephemeral</code>: an ephemeral curve25519 keypair that will only be used with this message.</li> | |
116 | - <li><code>body_key</code>: a random key that will be used to encrypt the plaintext body.</li> | |
117 | - </ul> | |
118 | - <p> | |
119 | - First, private-box outputs the ephemeral public key, then multiplies each recipient public key | |
120 | - with its secret to produce ephemeral shared keys (<code>shared_keys[1..n]</code>). | |
121 | - Then, private-box concatenates <code>body_key</code> with the number of recipients, | |
122 | - encrypts that to each shared key, and concatenates the encrypted body. | |
123 | - </p> | |
124 | - ${ com.code({ js: ` | |
125 | -function encrypt (plaintext, recipients) { | |
126 | - var ephemeral = keypair() | |
127 | - var nonce = random(24) | |
128 | - var body_key = random(32) | |
129 | - var body_key_with_length = concat([ | |
130 | - body_key, | |
131 | - recipients.length | |
132 | - ]) | |
133 | - return concat([ | |
134 | - nonce, | |
135 | - ephemeral.publicKey, | |
136 | - concat(recipients.map(function (publicKey) { | |
137 | - return secretbox( | |
138 | - body_key_with_length, | |
139 | - nonce, | |
140 | - scalarmult(publicKey, ephemeral.secretKey) | |
141 | - ) | |
142 | - }), | |
143 | - secretbox(plaintext, nonce, body_key) | |
144 | - ]) | |
145 | -}` }) } | |
146 | - | |
147 | - <h4 id="-decryption-">Decryption</h4> | |
148 | - <p> | |
149 | - <code>private-box</code> takes the nonce and ephemeral public key, | |
150 | - multiplies that with your secret key, then tests each possible | |
151 | - recipient slot until it either decrypts a key or runs out of slots. | |
152 | - If it runs out of slots, the message was not addressed to you, | |
153 | - so <code>undefined</code> is returned. Else, the message is found and the body | |
154 | - is decrypted. | |
155 | - </p> | |
156 | - ${ com.code({ js: ` | |
157 | -function decrypt (cyphertext, secretKey) { | |
158 | - var next = reader(cyphertext) // next() will read | |
159 | - // the passed N bytes | |
160 | - var nonce = next(24) | |
161 | - var publicKey = next(32) | |
162 | - var sharedKey = salarmult(publicKey, secretKey) | |
163 | - | |
164 | - for(var i = 0; i < 7; i++) { | |
165 | - var maybe_key = next(33) | |
166 | - var key_with_length = secretbox_open( | |
167 | - maybe_key, | |
168 | - nonce, | |
169 | - sharedKey | |
170 | - ) | |
171 | - if (key_with_length) { // decrypted! | |
172 | - var key = key_with_length.slice(0, 32) | |
173 | - var length = key_with_length[32] | |
174 | - return secretbox_open( | |
175 | - key, | |
176 | - cyphertext.slice( | |
177 | - 56 + 33*(length+1), | |
178 | - cyphertext.length | |
179 | - ), | |
180 | - ) | |
181 | - } | |
182 | - } | |
183 | - // this message was not addressed | |
184 | - // to the owner of secretKey | |
185 | - return undefined | |
186 | -}` }) } | |
187 | - | |
188 | - <p class="next"><a href="/modules/ssb-client.html">SSB-Client</a></p> | |
189 | - ` | |
190 | -}) |
tmpl/guides/concepts/secret-handshake.html.js | ||
---|---|---|
@@ -1,16 +1,0 @@ | ||
1 | -var page = require('../../page.part') | |
2 | -module.exports = () => page({ | |
3 | - section: 'docs', | |
4 | - tab: 'guides-concepts', | |
5 | - path: '/protocols/secret-handshake.html', | |
6 | - content: ` | |
7 | - <h2>Secret Handshake</h1> | |
8 | - <p> | |
9 | - Secret Handshake is an encrypted channel protocol based on a mutually authenticating key agreement handshake, with forward secure identity metadata. | |
10 | - It's used by Scuttlebot to authenticate and encrypt peer connections. | |
11 | - </p> | |
12 | - <p><a href="/protocols/shs.pdf">Read the White Paper</a></p> | |
13 | - | |
14 | - <p class="next"><a href="/protocols/private-box.html">Private Box</a></p> | |
15 | - ` | |
16 | -}) |
tmpl/guides/concepts/secure-scuttlebutt.html.js | ||
---|---|---|
@@ -1,150 +1,0 @@ | ||
1 | -var page = require('../../page.part') | |
2 | -var com = require('../../com.part') | |
3 | - | |
4 | -module.exports = () => page({ | |
5 | - section: 'docs', | |
6 | - tab: 'guides-concepts', | |
7 | - path: '/protocols/secure-scuttlebutt.html', | |
8 | - content: ` | |
9 | - <h2>Secure Scuttlebutt</h2> | |
10 | - <p>Secure Scuttlebutt is a database protocol for unforgeable append-only message feeds.</p> | |
11 | - <p> | |
12 | - "Unforgeable" means that only the owner of a feed can update that feed, as enforced by digital signing (see <a href="#security-properties">Security properties</a>). | |
13 | - This property makes Secure Scuttlebutt useful for peer-to-peer applications. | |
14 | - Secure Scuttlebutt also makes it easy to encrypt messages. | |
15 | - </p> | |
16 | - | |
17 | - <hr> | |
18 | - | |
19 | - <h2 id="concepts">Concepts</h2> | |
20 | - <p>Building upon Secure Scuttlebutt requires understanding a few concepts that it uses to ensure the unforgeability of message feeds.</p> | |
21 | - | |
22 | - <h3 id="identities">Identities</h3> | |
23 | - <p> | |
24 | - An identity is simply a <a href="http://ed25519.cr.yp.to/">ed25519 key pair</a>. | |
25 | - The public key is used as the identifier. | |
26 | - </p> | |
27 | - <p> | |
28 | - There is no worldwide store of identities. | |
29 | - Users must exchange pubkeys, either by publishing them on their feeds, or out-of-band. | |
30 | - </p> | |
31 | - | |
32 | - <h3 id="feeds">Feeds</h3> | |
33 | - <p> | |
34 | - A feed is a signed append-only sequence of messages. | |
35 | - Each identity has exactly one feed. | |
36 | - </p> | |
37 | - <p> | |
38 | - Note that append-only means you cannot delete an existing message, or change your history. | |
39 | - This is enforced by a per-feed blockchain. | |
40 | - This is to ensure the entire network converges on the same state. | |
41 | - </p> | |
42 | - | |
43 | - <h3 id="messages">Messages</h3> | |
44 | - <p>Each message contains:</p> | |
45 | - <ul> | |
46 | - <li>A signature</li> | |
47 | - <li>The signing public key</li> | |
48 | - <li>A content-hash of the previous message</li> | |
49 | - <li>A sequence number</li> | |
50 | - <li>A timestamp</li> | |
51 | - <li>An identifier of the hashing algorithm in use (currently only "sha256" is supported)</li> | |
52 | - <li>A content object</li> | |
53 | - </ul> | |
54 | - <p>Here's an example message:</p> | |
55 | - ${ com.code({ js: `{ | |
56 | - "previous": "%26AC+gU0t74jRGVeDY01...MnutGGHM=.sha256", | |
57 | - "author": "@hxGxqPrplLjRG2vtjQL87...0nNwE=.ed25519", | |
58 | - "sequence": 216, | |
59 | - "timestamp": 1442590513298, | |
60 | - "hash": "sha256", | |
61 | - "content": { | |
62 | - "type": "vote", | |
63 | - "vote": { | |
64 | - "link": "%WbQ4dq0m/zu5jxll9zUb...KjZ80JvI=.sha256", | |
65 | - "value": 1 | |
66 | - } | |
67 | - }, | |
68 | - "signature": "Sjq1C3yiKdmi1TWvNqxI...gmAQ==.sig.ed25519" | |
69 | -}` }) } | |
70 | - | |
71 | - <h3 id="entity-references-links-">Entity References (Links)</h3> | |
72 | - <p> | |
73 | - Messages can reference three types of Secure Scuttlebutt entities: messages, feeds, and blobs (i.e. files). | |
74 | - Messages and blobs are referred to by their hashes, but a feed is referred to by its signing public key. | |
75 | - </p> | |
76 | - | |
77 | - <h3 id="confidentiality">Confidentiality</h3> | |
78 | - <p> | |
79 | - For private sharing, Scuttlebot uses <a href="http://doc.libsodium.org/">libsodium</a> to encrypt confidential log-entries. | |
80 | - Feed IDs are public keys, and so once two feeds are mutually following each other, they can exchange confidential data freely. | |
81 | - </p> | |
82 | - | |
83 | - <h3 id="following">Following</h3> | |
84 | - <p> | |
85 | - Users choose which feeds to synchronize by following them. | |
86 | - Presently, <a href="/modules/scuttlebot-replicate.html">Scuttlebot's replicate plugin</a>, which is enabled by default, looks on the master user's feed for <code>type:contact</code> messages to know which users are currently followed. | |
87 | - </p> | |
88 | - | |
89 | - <h3 id="replication">Replication</h3> | |
90 | - <p> | |
91 | - Since feeds are append-only, replication is simple: request all messages in the feed that are newer than the latest message you know about. | |
92 | - Scuttlebot maintains a table of known peers, which it cycles through, asking for updates for all followed feeds. | |
93 | - </p> | |
94 | - | |
95 | - <h3 id="gossip">Gossip</h3> | |
96 | - <p> | |
97 | - The protocol creates a <a href="https://en.wikipedia.org/wiki/Gossip_protocol">global gossip network</a>. | |
98 | - This means that information is able to distribute across multiple machines, without requiring direct connections between them. | |
99 | - </p> | |
100 | - <p><img src="/img/gossip-graph1.png" alt="Gossip graph"></p> | |
101 | - <p>Even though Alice and Dan lack a direct connection, they can still exchange feeds:</p> | |
102 | - <p><img src="/img/gossip-graph2.png" alt="Gossip graph 2"></p> | |
103 | - <p> | |
104 | - This is because gossip creates "transitive" connections between computers. | |
105 | - Dan's messages travel through Carla and the Pub to reach Alice, and visa-versa. | |
106 | - </p> | |
107 | - | |
108 | - <h3 id="lan-connectivity">LAN connectivity</h3> | |
109 | - <p> | |
110 | - SSB is hostless: each computer installs the same copy of software and has equal rights in the network. | |
111 | - Devices discover each other over the LAN with multicast UDP and sync automatically. | |
112 | - </p> | |
113 | - | |
114 | - <h3 id="pub-servers">Pub Servers</h3> | |
115 | - <p> | |
116 | - To sync across the Internet, "Pub" nodes run at public IPs and follow users. | |
117 | - They are essentially mail-bots which improve uptime and availability. | |
118 | - Users generate invite-codes to command Pubs to follow their friends. | |
119 | - The Scuttlebot community runs some Pubs, and anybody can create and introduce their own. | |
120 | - </p> | |
121 | - | |
122 | - <h2 id="security-properties">Security properties</h2> | |
123 | - <p> | |
124 | - Secure Scuttlebutt maintains useful security properties even when it is connected to a malicious Secure Scuttlebutt database. | |
125 | - This makes it ideal as a store for peer-to-peer applications. | |
126 | - </p> | |
127 | - <p> | |
128 | - Imagine that we want to read from a feed for which we know the identity, but we're connected to a malicious Secure Scuttlebutt instance. | |
129 | - As long as the malicious database does not have the private key: | |
130 | - </p> | |
131 | - <ul> | |
132 | - <li>The malicious database cannot create a new feed with the same identifier</li> | |
133 | - <li>The malicious database cannot write new fake messages to the feed</li> | |
134 | - <li>The malicious database cannot reorder the messages in the feed</li> | |
135 | - <li>The malicious database cannot send us a new copy of the feed that omits messages from the middle</li> | |
136 | - <li>The malicious database <em>can</em> refuse to send us the feed, or only send us the first <em>N</em> messages in the feed</li> | |
137 | - <li>Messages may optionally be encrypted</li> | |
138 | - </ul> | |
139 | - <p> | |
140 | - Additionally there is a protection from the feed owner, through the blockchain. | |
141 | - The <code>previous</code> content-hash them from changing the feed history after publishing, as a newly-created message wouldn't match the hash of later messages which were already replicated. | |
142 | - This ensures the append-only constraint, and thus safe network convergence. | |
143 | - </p> | |
144 | - | |
145 | - <p class="next"><a href="/protocols/secret-handshake.html">Secret Handshake</a></p> | |
146 | - <ul class="see-also"> | |
147 | - <li><a href="/docs/social/social-network.html">Social Network</a></li> | |
148 | - </ul> | |
149 | - ` | |
150 | -}) |
tmpl/guides/concepts/shs.pdf | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 219079 bytes New file size: 0 bytes |
tmpl/guides/concepts/social.html.js | ||
---|---|---|
@@ -1,47 +1,0 @@ | ||
1 | -var page = require('../../page.part') | |
2 | -module.exports = () => page({ | |
3 | - section: 'docs', | |
4 | - tab: 'guides-concepts', | |
5 | - path: '/social/social-network.html', | |
6 | - content: ` | |
7 | - <h2>Social network</h2> | |
8 | - <p> | |
9 | - Scuttlebot forms a global cryptographic social network with its peers. | |
10 | - Each user is identified by a public key, and publishes a log of signed messages, which other users "follow." | |
11 | - </p> | |
12 | - <p> | |
13 | - Scuttlebot searches the P2P mesh for new messages and files from followed users and from FoaFs. | |
14 | - The messages and files are stored locally, indefinitely, for applications to read. | |
15 | - </p> | |
16 | - | |
17 | - <h3>Identity</h3> | |
18 | - <p> | |
19 | - Users are identified by confirmations in the social graph. | |
20 | - This is known as a Web-of-Trust. | |
21 | - There is no global registry of usernames. | |
22 | - Instead, users name themselves, and share petnames for each other. | |
23 | - </p> | |
24 | - <p> | |
25 | - Discovery occurs by examining the social graph, or by out-of-band sharing. | |
26 | - Applications can analyze the follow-graph, and look for "flag" messages, to determine who is trust-worthy in the network. | |
27 | - </p> | |
28 | - | |
29 | - <h3>Pub Servers</h3> | |
30 | - <p> | |
31 | - "Pubs" are bot-users that have public IPs. | |
32 | - They follow users and rehost the messages to other peers, ensuring good uptime and no firewall blockage. | |
33 | - </p> | |
34 | - <p> | |
35 | - Pubs have no special privileges, and are not trusted by users. | |
36 | - However, because Scuttlebot has no DHT or NAT-traversal utilities, users must "join" a Pub to distribute their messages on the WAN. | |
37 | - </p> | |
38 | - <p> | |
39 | - Scuttlebot can change Pubs, or join more than one, and sync directly over Wifi. | |
40 | - Identity is not tied to the Pubs. | |
41 | - </p> | |
42 | - <p class="next"><a href="/docs/social/follow-users.html">Follow users</a></p> | |
43 | - <ul class="see-also"> | |
44 | - <li><a href="/whitepapers/secure-scuttlebutt.html">Secure Scuttlebutt</a></li> | |
45 | - </ul> | |
46 | - ` | |
47 | -}) |
tmpl/guides/protocols/private-box.html.js | ||
---|---|---|
@@ -1,0 +1,188 @@ | ||
1 | +var page = require('../../page.part') | |
2 | +var com = require('../../com.part') | |
3 | + | |
4 | +module.exports = () => page({ | |
5 | + section: 'guides', | |
6 | + tab: 'guides-protocols', | |
7 | + path: '/guides/protocols/private-box.html', | |
8 | + content: ` | |
9 | + <h2>Private Box</h2> | |
10 | + <p> | |
11 | + Private-box is a format for encrypting a private message to many parties. | |
12 | + You can <strong><a href="https://github.com/auditdrivencrypto/private-box">find the repository on GitHub</a></strong>. | |
13 | + </p> | |
14 | + | |
15 | + <h2 id="properties">Properties</h2> | |
16 | + <p> | |
17 | + This protocol was designed for use with secure-scuttlebutt. | |
18 | + In this place, messages are placed in public, and the sender is known via a signature, | |
19 | + but we can hide the recipient and the content. | |
20 | + </p> | |
21 | + | |
22 | + <h4 id="-recipients-are-hidden-">Recipients are hidden.</h4> | |
23 | + <p> | |
24 | + An eaves-dropper cannot know the recipients or their number. | |
25 | + Since the message is encrypted to each recipient, and then placed in public, | |
26 | + to receive a message you will have to decrypt every message posted. | |
27 | + This would not be scalable if you had to decrypt every message on the internet, | |
28 | + but if you can restrict the number of messages you might have to decrypt, | |
29 | + then it's reasonable. For example, if you frequented a forum which contained these messages, | |
30 | + then it would only be a reasonable number of messages, and posting a message would only | |
31 | + reveal that you where talking to some other member of that forum. | |
32 | + </p> | |
33 | + <p>Hiding access to such a forum is another problem that's out of the current scope.</p> | |
34 | + | |
35 | + <h4 id="-the-number-of-recipients-are-hidden-">The number of recipients are hidden.</h4> | |
36 | + <p> | |
37 | + If the number of recipients was not hidden, then sometimes it would be possible | |
38 | + to deanonymise the recipients, if there was a large group discussion with | |
39 | + an unusual number of recipients. Encrypting the number of recipients means that, | |
40 | + when a message is not encrypted to you, you will attempt to decrypt same number of times | |
41 | + as the maximum recipients. | |
42 | + </p> | |
43 | + | |
44 | + <h4 id="-a-valid-recipient-does-not-know-the-other-recipients-">A valid recipient does not know the other recipients.</h4> | |
45 | + <p> | |
46 | + A valid recipient knows the number of recipients but now who they are. | |
47 | + This is more a sideeffect of the design than an intentional design element. | |
48 | + The plaintext contents may reveal the recipients, if needed. | |
49 | + </p> | |
50 | + | |
51 | + <h4 id="-by-providing-the-key-for-a-message-an-outside-party-could-decrypt-the-message-">By providing the key for a message, an outside party could decrypt the message.</h4> | |
52 | + <p> | |
53 | + When you tell someone a secret you must trust them not to reveal it. | |
54 | + Anyone who knows the key could reveal that to some other party who could then read the message content, | |
55 | + but not the recipients (unless the sender revealed the ephemeral secret key). | |
56 | + </p> | |
57 | + | |
58 | + <h2 id="assumptions">Assumptions</h2> | |
59 | + <p> | |
60 | + Messages will be posted in public, so that the sender is likely to be known, | |
61 | + and everyone can read the messages. (This makes it possible to hide the recipient, | |
62 | + but probably not the sender.) | |
63 | + </p> | |
64 | + <p>Resisting traffic analysis of the timing or size of messages is out of scope of this spec.</p> | |
65 | + | |
66 | + <h2 id="prior-art">Prior Art</h2> | |
67 | + <h4 id="-pgp-">PGP</h4> | |
68 | + <p> | |
69 | + In PGP the recipient, the sender, and the subject are sent as plaintext. | |
70 | + If the recipient is known, then the metadata graph of who is communicating with who can be read, | |
71 | + which, since it is easier to analyze than the content, is important to protect. | |
72 | + </p> | |
73 | + <h4 id="-sodium-seal-">Sodium seal</h4> | |
74 | + <p> | |
75 | + The Sodium library provides a <em>seal</em> function that generates an ephemeral keypair, | |
76 | + derives a shared key to encrypt a message, and then sends the ephemeral public key and the message. | |
77 | + The recipient is hidden, and it is forward secure if the sender throws out the ephemeral key. | |
78 | + However, it's only possible to have one recipient. | |
79 | + </p> | |
80 | + | |
81 | + <h4 id="-minilock-">Minilock</h4> | |
82 | + <p> | |
83 | + Minilock uses a similar approach to <code>private-box</code> but does not hide the | |
84 | + number of recipients. In the case of a group discussion where multiple rounds | |
85 | + of messages are sent to everyone, this may enable an eavesdropper to deanonymize | |
86 | + the participiants of a discussion if the sender of each message is known. | |
87 | + </p> | |
88 | + | |
89 | + <h2 id="api">API</h2> | |
90 | + | |
91 | + <h4 id="-encrypt-plaintext-buffer-recipients-array-curve25519_pk-">encrypt (plaintext Buffer, recipients Array<curve25519_pk>)</h4> | |
92 | + <p> | |
93 | + Takes a plaintext buffer of the message you want to encrypt, | |
94 | + and an array of recipient public keys. | |
95 | + Returns a message that is encrypted to all recipients | |
96 | + and openable by them with <code>PrivateBox.decrypt</code>. | |
97 | + The recipients must be between 1 and 7 items long. | |
98 | + </p> | |
99 | + <p> | |
100 | + The encrypted length will be <code>56 + (recipients.length * 33) + plaintext.length</code> bytes long, | |
101 | + between 89 and 287 bytes longer than the plaintext. | |
102 | + </p> | |
103 | + | |
104 | + <h4 id="-decrypt-cyphertext-buffer-secretkey-curve25519_sk-">decrypt (cyphertext Buffer, secretKey curve25519_sk)</h4> | |
105 | + <p> | |
106 | + Attempt to decrypt a private-box message, using your secret key. | |
107 | + If you where an intended recipient then the plaintext will be returned. | |
108 | + If it was not for you, then <code>undefined</code> will be returned. | |
109 | + </p> | |
110 | + | |
111 | + <h2 id="protocol">Protocol</h2> | |
112 | + <h4 id="-encryption-">Encryption</h4> | |
113 | + <p>Private-box generates:</p> | |
114 | + <ul> | |
115 | + <li><code>ephemeral</code>: an ephemeral curve25519 keypair that will only be used with this message.</li> | |
116 | + <li><code>body_key</code>: a random key that will be used to encrypt the plaintext body.</li> | |
117 | + </ul> | |
118 | + <p> | |
119 | + First, private-box outputs the ephemeral public key, then multiplies each recipient public key | |
120 | + with its secret to produce ephemeral shared keys (<code>shared_keys[1..n]</code>). | |
121 | + Then, private-box concatenates <code>body_key</code> with the number of recipients, | |
122 | + encrypts that to each shared key, and concatenates the encrypted body. | |
123 | + </p> | |
124 | + ${ com.code({ js: ` | |
125 | +function encrypt (plaintext, recipients) { | |
126 | + var ephemeral = keypair() | |
127 | + var nonce = random(24) | |
128 | + var body_key = random(32) | |
129 | + var body_key_with_length = concat([ | |
130 | + body_key, | |
131 | + recipients.length | |
132 | + ]) | |
133 | + return concat([ | |
134 | + nonce, | |
135 | + ephemeral.publicKey, | |
136 | + concat(recipients.map(function (publicKey) { | |
137 | + return secretbox( | |
138 | + body_key_with_length, | |
139 | + nonce, | |
140 | + scalarmult(publicKey, ephemeral.secretKey) | |
141 | + ) | |
142 | + }), | |
143 | + secretbox(plaintext, nonce, body_key) | |
144 | + ]) | |
145 | +}` }) } | |
146 | + | |
147 | + <h4 id="-decryption-">Decryption</h4> | |
148 | + <p> | |
149 | + <code>private-box</code> takes the nonce and ephemeral public key, | |
150 | + multiplies that with your secret key, then tests each possible | |
151 | + recipient slot until it either decrypts a key or runs out of slots. | |
152 | + If it runs out of slots, the message was not addressed to you, | |
153 | + so <code>undefined</code> is returned. Else, the message is found and the body | |
154 | + is decrypted. | |
155 | + </p> | |
156 | + ${ com.code({ js: ` | |
157 | +function decrypt (cyphertext, secretKey) { | |
158 | + var next = reader(cyphertext) // next() will read | |
159 | + // the passed N bytes | |
160 | + var nonce = next(24) | |
161 | + var publicKey = next(32) | |
162 | + var sharedKey = salarmult(publicKey, secretKey) | |
163 | + | |
164 | + for(var i = 0; i < 7; i++) { | |
165 | + var maybe_key = next(33) | |
166 | + var key_with_length = secretbox_open( | |
167 | + maybe_key, | |
168 | + nonce, | |
169 | + sharedKey | |
170 | + ) | |
171 | + if (key_with_length) { // decrypted! | |
172 | + var key = key_with_length.slice(0, 32) | |
173 | + var length = key_with_length[32] | |
174 | + return secretbox_open( | |
175 | + key, | |
176 | + cyphertext.slice( | |
177 | + 56 + 33*(length+1), | |
178 | + cyphertext.length | |
179 | + ), | |
180 | + ) | |
181 | + } | |
182 | + } | |
183 | + // this message was not addressed | |
184 | + // to the owner of secretKey | |
185 | + return undefined | |
186 | +}` }) } | |
187 | + ` | |
188 | +}) |
tmpl/guides/protocols/secret-handshake.html.js | ||
---|---|---|
@@ -1,0 +1,15 @@ | ||
1 | +var page = require('../../page.part') | |
2 | +module.exports = () => page({ | |
3 | + section: 'guides', | |
4 | + tab: 'guides-protocols', | |
5 | + path: '/guides/protocols/secret-handshake.html', | |
6 | + content: ` | |
7 | + <h2>Secret Handshake</h1> | |
8 | + <p> | |
9 | + Secret Handshake is an encrypted channel protocol based on a mutually authenticating key agreement handshake, with forward secure identity metadata. | |
10 | + It's used by Scuttlebot to authenticate and encrypt peer connections. | |
11 | + </p> | |
12 | + <p><a href="./shs.pdf">Read the White Paper</a></p> | |
13 | + `, | |
14 | + next: ['/guides/protocols/private-box.html', 'Private Box'] | |
15 | +}) |
tmpl/guides/protocols/secure-scuttlebutt.html.js | ||
---|---|---|
@@ -1,0 +1,146 @@ | ||
1 | +var page = require('../../page.part') | |
2 | +var com = require('../../com.part') | |
3 | + | |
4 | +module.exports = () => page({ | |
5 | + section: 'guides', | |
6 | + tab: 'guides-protocols', | |
7 | + path: '/guides/protocols/secure-scuttlebutt.html', | |
8 | + content: ` | |
9 | + <h2>Secure Scuttlebutt</h2> | |
10 | + <p>Secure Scuttlebutt is a database protocol for unforgeable append-only message feeds.</p> | |
11 | + <p> | |
12 | + "Unforgeable" means that only the owner of a feed can update that feed, as enforced by digital signing (see <a href="#security-properties">Security properties</a>). | |
13 | + This property makes Secure Scuttlebutt useful for peer-to-peer applications. | |
14 | + Secure Scuttlebutt also makes it easy to encrypt messages. | |
15 | + </p> | |
16 | + | |
17 | + <hr> | |
18 | + | |
19 | + <h2 id="concepts">Concepts</h2> | |
20 | + <p>Building upon Secure Scuttlebutt requires understanding a few concepts that it uses to ensure the unforgeability of message feeds.</p> | |
21 | + | |
22 | + <h3 id="identities">Identities</h3> | |
23 | + <p> | |
24 | + An identity is simply a <a href="http://ed25519.cr.yp.to/">ed25519 key pair</a>. | |
25 | + The public key is used as the identifier. | |
26 | + </p> | |
27 | + <p> | |
28 | + There is no worldwide store of identities. | |
29 | + Users must exchange pubkeys, either by publishing them on their feeds, or out-of-band. | |
30 | + </p> | |
31 | + | |
32 | + <h3 id="feeds">Feeds</h3> | |
33 | + <p> | |
34 | + A feed is a signed append-only sequence of messages. | |
35 | + Each identity has exactly one feed. | |
36 | + </p> | |
37 | + <p> | |
38 | + Note that append-only means you cannot delete an existing message, or change your history. | |
39 | + This is enforced by a per-feed blockchain. | |
40 | + This is to ensure the entire network converges on the same state. | |
41 | + </p> | |
42 | + | |
43 | + <h3 id="messages">Messages</h3> | |
44 | + <p>Each message contains:</p> | |
45 | + <ul> | |
46 | + <li>A signature</li> | |
47 | + <li>The signing public key</li> | |
48 | + <li>A content-hash of the previous message</li> | |
49 | + <li>A sequence number</li> | |
50 | + <li>A timestamp</li> | |
51 | + <li>An identifier of the hashing algorithm in use (currently only "sha256" is supported)</li> | |
52 | + <li>A content object</li> | |
53 | + </ul> | |
54 | + <p>Here's an example message:</p> | |
55 | + ${ com.code({ js: `{ | |
56 | + "previous": "%26AC+gU0t74jRGVeDY01...MnutGGHM=.sha256", | |
57 | + "author": "@hxGxqPrplLjRG2vtjQL87...0nNwE=.ed25519", | |
58 | + "sequence": 216, | |
59 | + "timestamp": 1442590513298, | |
60 | + "hash": "sha256", | |
61 | + "content": { | |
62 | + "type": "vote", | |
63 | + "vote": { | |
64 | + "link": "%WbQ4dq0m/zu5jxll9zUb...KjZ80JvI=.sha256", | |
65 | + "value": 1 | |
66 | + } | |
67 | + }, | |
68 | + "signature": "Sjq1C3yiKdmi1TWvNqxI...gmAQ==.sig.ed25519" | |
69 | +}` }) } | |
70 | + | |
71 | + <h3 id="entity-references-links-">Entity References (Links)</h3> | |
72 | + <p> | |
73 | + Messages can reference three types of Secure Scuttlebutt entities: messages, feeds, and blobs (i.e. files). | |
74 | + Messages and blobs are referred to by their hashes, but a feed is referred to by its signing public key. | |
75 | + </p> | |
76 | + | |
77 | + <h3 id="confidentiality">Confidentiality</h3> | |
78 | + <p> | |
79 | + For private sharing, Scuttlebot uses <a href="http://doc.libsodium.org/">libsodium</a> to encrypt confidential log-entries. | |
80 | + Feed IDs are public keys, and so once two feeds are mutually following each other, they can exchange confidential data freely. | |
81 | + </p> | |
82 | + | |
83 | + <h3 id="following">Following</h3> | |
84 | + <p> | |
85 | + Users choose which feeds to synchronize by following them. | |
86 | + Presently, <a href="/modules/scuttlebot-replicate.html">Scuttlebot's replicate plugin</a>, which is enabled by default, looks on the master user's feed for <code>type:contact</code> messages to know which users are currently followed. | |
87 | + </p> | |
88 | + | |
89 | + <h3 id="replication">Replication</h3> | |
90 | + <p> | |
91 | + Since feeds are append-only, replication is simple: request all messages in the feed that are newer than the latest message you know about. | |
92 | + Scuttlebot maintains a table of known peers, which it cycles through, asking for updates for all followed feeds. | |
93 | + </p> | |
94 | + | |
95 | + <h3 id="gossip">Gossip</h3> | |
96 | + <p> | |
97 | + The protocol creates a <a href="https://en.wikipedia.org/wiki/Gossip_protocol">global gossip network</a>. | |
98 | + This means that information is able to distribute across multiple machines, without requiring direct connections between them. | |
99 | + </p> | |
100 | + <p><img src="/img/gossip-graph1.png" alt="Gossip graph"></p> | |
101 | + <p>Even though Alice and Dan lack a direct connection, they can still exchange feeds:</p> | |
102 | + <p><img src="/img/gossip-graph2.png" alt="Gossip graph 2"></p> | |
103 | + <p> | |
104 | + This is because gossip creates "transitive" connections between computers. | |
105 | + Dan's messages travel through Carla and the Pub to reach Alice, and visa-versa. | |
106 | + </p> | |
107 | + | |
108 | + <h3 id="lan-connectivity">LAN connectivity</h3> | |
109 | + <p> | |
110 | + SSB is hostless: each computer installs the same copy of software and has equal rights in the network. | |
111 | + Devices discover each other over the LAN with multicast UDP and sync automatically. | |
112 | + </p> | |
113 | + | |
114 | + <h3 id="pub-servers">Pub Servers</h3> | |
115 | + <p> | |
116 | + To sync across the Internet, "Pub" nodes run at public IPs and follow users. | |
117 | + They are essentially mail-bots which improve uptime and availability. | |
118 | + Users generate invite-codes to command Pubs to follow their friends. | |
119 | + The Scuttlebot community runs some Pubs, and anybody can create and introduce their own. | |
120 | + </p> | |
121 | + | |
122 | + <h2 id="security-properties">Security properties</h2> | |
123 | + <p> | |
124 | + Secure Scuttlebutt maintains useful security properties even when it is connected to a malicious Secure Scuttlebutt database. | |
125 | + This makes it ideal as a store for peer-to-peer applications. | |
126 | + </p> | |
127 | + <p> | |
128 | + Imagine that we want to read from a feed for which we know the identity, but we're connected to a malicious Secure Scuttlebutt instance. | |
129 | + As long as the malicious database does not have the private key: | |
130 | + </p> | |
131 | + <ul> | |
132 | + <li>The malicious database cannot create a new feed with the same identifier</li> | |
133 | + <li>The malicious database cannot write new fake messages to the feed</li> | |
134 | + <li>The malicious database cannot reorder the messages in the feed</li> | |
135 | + <li>The malicious database cannot send us a new copy of the feed that omits messages from the middle</li> | |
136 | + <li>The malicious database <em>can</em> refuse to send us the feed, or only send us the first <em>N</em> messages in the feed</li> | |
137 | + <li>Messages may optionally be encrypted</li> | |
138 | + </ul> | |
139 | + <p> | |
140 | + Additionally there is a protection from the feed owner, through the blockchain. | |
141 | + The <code>previous</code> content-hash them from changing the feed history after publishing, as a newly-created message wouldn't match the hash of later messages which were already replicated. | |
142 | + This ensures the append-only constraint, and thus safe network convergence. | |
143 | + </p> | |
144 | + `, | |
145 | + next: ['/guides/protocols/secret-handshake.html', 'Secret Handshake'] | |
146 | +}) |
tmpl/guides/protocols/shs.pdf | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 0 bytes New file size: 219079 bytes |
tmpl/guides/protocols/social.html.js | ||
---|---|---|
@@ -1,0 +1,47 @@ | ||
1 | +var page = require('../../page.part') | |
2 | +module.exports = () => page({ | |
3 | + section: 'docs', | |
4 | + tab: 'guides-protocols', | |
5 | + path: '/social/social-network.html', | |
6 | + content: ` | |
7 | + <h2>Social network</h2> | |
8 | + <p> | |
9 | + Scuttlebot forms a global cryptographic social network with its peers. | |
10 | + Each user is identified by a public key, and publishes a log of signed messages, which other users "follow." | |
11 | + </p> | |
12 | + <p> | |
13 | + Scuttlebot searches the P2P mesh for new messages and files from followed users and from FoaFs. | |
14 | + The messages and files are stored locally, indefinitely, for applications to read. | |
15 | + </p> | |
16 | + | |
17 | + <h3>Identity</h3> | |
18 | + <p> | |
19 | + Users are identified by confirmations in the social graph. | |
20 | + This is known as a Web-of-Trust. | |
21 | + There is no global registry of usernames. | |
22 | + Instead, users name themselves, and share petnames for each other. | |
23 | + </p> | |
24 | + <p> | |
25 | + Discovery occurs by examining the social graph, or by out-of-band sharing. | |
26 | + Applications can analyze the follow-graph, and look for "flag" messages, to determine who is trust-worthy in the network. | |
27 | + </p> | |
28 | + | |
29 | + <h3>Pub Servers</h3> | |
30 | + <p> | |
31 | + "Pubs" are bot-users that have public IPs. | |
32 | + They follow users and rehost the messages to other peers, ensuring good uptime and no firewall blockage. | |
33 | + </p> | |
34 | + <p> | |
35 | + Pubs have no special privileges, and are not trusted by users. | |
36 | + However, because Scuttlebot has no DHT or NAT-traversal utilities, users must "join" a Pub to distribute their messages on the WAN. | |
37 | + </p> | |
38 | + <p> | |
39 | + Scuttlebot can change Pubs, or join more than one, and sync directly over Wifi. | |
40 | + Identity is not tied to the Pubs. | |
41 | + </p> | |
42 | + <p class="next"><a href="/docs/social/follow-users.html">Follow users</a></p> | |
43 | + <ul class="see-also"> | |
44 | + <li><a href="/whitepapers/secure-scuttlebutt.html">Secure Scuttlebutt</a></li> | |
45 | + </ul> | |
46 | + ` | |
47 | +}) |
tmpl/index.html.js | ||
---|---|---|
@@ -22,9 +22,9 @@ | ||
22 | 22 | Localhosted frontend applications read and write freely to the local instance, and, in the background, the database syncs with known peers.<br> |
23 | 23 | <br> |
24 | 24 | Users are identified by public keys, and follow each other to form a web-of-trust. |
25 | 25 | Peers do not have to be trusted, and can share logs and files on behalf of other peers. |
26 | - <a href="/protocols/secure-scuttlebutt.html">Read about the protocol.</a> | |
26 | + <a href="/guides/protocols/secure-scuttlebutt.html">Read about the protocol.</a> | |
27 | 27 | </p> |
28 | 28 | </div> |
29 | 29 | `, |
30 | 30 | content: installTheDatabase.content() |
tmpl/leftnav.part.js | ||
---|---|---|
@@ -104,10 +104,12 @@ | ||
104 | 104 | ${item(c, '/apis/community/ssb-notifier.html', 'SSB-Notifier')} |
105 | 105 | ${item(c, '/apis/community/patchwork-threads.html', 'Patchwork-Threads')} |
106 | 106 | </ul>` |
107 | 107 | |
108 | -module.exports['guides-concepts'] = (c) => `<ul class="nav"> | |
109 | - ${item(c, '/guides/concepts/intro.html', 'Intro')} | |
108 | +module.exports['guides-protocols'] = (c) => `<ul class="nav"> | |
109 | + ${item(c, '/guides/protocols/secure-scuttlebutt.html', 'Secure Scuttlebutt')} | |
110 | + ${item(c, '/guides/protocols/secret-handshake.html', 'Secret Handshake')} | |
111 | + ${item(c, '/guides/protocols/private-box.html', 'Private Box')} | |
110 | 112 | </ul>` |
111 | 113 | |
112 | 114 | module.exports['guides-how-to-use-pull-streams'] = (c) => `<ul class="nav"> |
113 | 115 | ${item(c, '/guides/how-to-use-pull-streams/intro.html', 'Intro')} |
tmpl/tabs.part.js | ||
---|---|---|
@@ -8,9 +8,9 @@ | ||
8 | 8 | module.exports.sections = (c) => `<div class="tabs big"> |
9 | 9 | ${item(c, 'docs', '/docs/basics/install-the-database.html', 'Docs')} |
10 | 10 | ${item(c, 'apis', '/apis/scuttlebot/ssb.html', 'APIs')} |
11 | 11 | ${item(c, 'apps', '/apps/patchwork.html', 'Apps')} |
12 | - ${item(c, 'guides', '/guides/what-can-you-build-with-sbot/intro.html', 'Guides')} | |
12 | + ${item(c, 'guides', '/guides/protocols/secure-scuttlebutt.html', 'Guides')} | |
13 | 13 | </div>` |
14 | 14 | |
15 | 15 | module.exports.docs = (c) => `<div class="tabs small"> |
16 | 16 | ${item(c, 'docs-basics', '/docs/basics/install-the-database.html', 'Basics')} |
@@ -35,10 +35,9 @@ | ||
35 | 35 | ${item(c, 'protocols', '/protocols/secure-scuttlebutt.html', 'Protocols')} |
36 | 36 | </div>` |
37 | 37 | |
38 | 38 | module.exports.guides = (c) => `<div class="tabs small"> |
39 | - ${item(c, 'basics', '/basics/install-the-database.html', 'Basics')} | |
40 | - ${item(c, 'social', '/social/social-network.html', 'Social')} | |
41 | - ${item(c, 'messages', '/messages/post.html', 'Message Types')} | |
42 | - ${item(c, 'advanced', '/advanced/writing-applications.html', 'Advanced')} | |
43 | - ${item(c, 'protocols', '/protocols/secure-scuttlebutt.html', 'Protocols')} | |
39 | + ${item(c, 'guides-protocols', '/guides/protocols/secure-scuttlebutt.html', 'Protocols')} | |
40 | + ${item(c, 'guides-social-feed=app', '/social/social-network.html', 'Social Feed App')} | |
41 | + ${item(c, 'private messaging app', '/messages/post.html', 'Private Messaging App')} | |
42 | + ${item(c, 'todo list app', '/advanced/writing-applications.html', 'Todo List App')} | |
44 | 43 | </div>` |
Built with git-ssb-web