Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FCP HIPE: Wire Messages (formerly AMES) #43

Merged
merged 61 commits into from
Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
659d3cb
added description of AnonCrypt and AuthCrypt
kdenhartog Jul 13, 2018
af5e21e
reversed sender and random priv_key in step 3
kdenhartog Aug 6, 2018
1018805
Merge branch 'master' of github.com:hyperledger/indy-hipe
kdenhartog Aug 6, 2018
345c5c1
Initial version of Wire Message HIPE
swcurran Aug 17, 2018
876092b
Clarifying the requirements of the unpack() when using the authcrypt
swcurran Aug 20, 2018
8fcce07
Args to pack() must include myPubKey when AuthCrypt being used
swcurran Aug 20, 2018
d5e5001
Merge branch 'master' of github.com:swcurran/indy-hipe
kdenhartog Aug 21, 2018
f23d11e
Merge branch 'wireMessages' of github.com:swcurran/indy-hipe
kdenhartog Aug 21, 2018
15baaca
fixed prior art sections to match implementation details
kdenhartog Sep 17, 2018
4178bcc
Merge branch 'master' of github.com:hyperledger/indy-hipe
kdenhartog Sep 18, 2018
1b7f276
AMES (aka JWMs) HIPE
kdenhartog Sep 18, 2018
6942efa
updated summary
kdenhartog Sep 18, 2018
1c39f47
fixed location and removed non-accepted hipes
kdenhartog Sep 18, 2018
32681b5
updated unpack API
kdenhartog Sep 18, 2018
3035b33
separated Route Table work - will go in separate HIPE
kdenhartog Sep 20, 2018
a2d5214
Removed route table docs, will move to separate hipe
kdenhartog Sep 20, 2018
db5de9a
moved hipe to text directory only
kdenhartog Sep 20, 2018
08ed97d
updated motivations; removed other mention of route tables
kdenhartog Sep 20, 2018
36a6dcf
Added link to code to track progress
kdenhartog Sep 20, 2018
1255ed8
updated HIPE to fit API format
kdenhartog Oct 1, 2018
1d0486f
updated HIPE to align with code
kdenhartog Oct 1, 2018
96bd569
Merge branch 'master' into AMES
kdenhartog Oct 1, 2018
fbf8e09
Added additonal questions section
kdenhartog Oct 2, 2018
803b4dd
merge master
kdenhartog Oct 2, 2018
e6ac023
added additional descriptions which now support encrypting headers
kdenhartog Oct 3, 2018
df12b40
reformat to find sections easier
kdenhartog Oct 3, 2018
2293dab
updated to detail new changes needed for restructed data and encrypti…
kdenhartog Oct 4, 2018
4bb7c8c
updated to reflect code
kdenhartog Oct 6, 2018
ef9a8ef
updated cek to e_cek in json
kdenhartog Oct 6, 2018
d6f154d
updated hipe to align with Wire message HIPE and Mike Lodder's format
kdenhartog Nov 12, 2018
359ff79
Merge branch 'master' into AMES
kdenhartog Nov 12, 2018
e3e5fa7
additional updates - added more authors
kdenhartog Nov 12, 2018
5987dc7
Merge branch 'AMES' of github.com:kdenhartog/indy-hipe into AMES
kdenhartog Nov 12, 2018
66e7ec0
updated HIPE for new definitions alignment
kdenhartog Nov 30, 2018
fb50931
added additional details from original wire message HIPE
kdenhartog Nov 30, 2018
99b83b3
ready for FCP
kdenhartog Dec 3, 2018
fa61b61
fixed minor details
kdenhartog Dec 4, 2018
44c1f31
Merge branch 'master' into AMES
kdenhartog Dec 4, 2018
3357b5a
updates from FCP comments
kdenhartog Dec 7, 2018
f167dc0
Merge branch 'AMES' of github.com:kdenhartog/indy-hipe into AMES
kdenhartog Dec 7, 2018
0999bc8
fix typo
kdenhartog Dec 7, 2018
71a3d36
updated feature branch
kdenhartog Dec 7, 2018
bc7e4be
updated to match indy-SDK implementation
kdenhartog Dec 11, 2018
c63f0ab
removed algorithms that won't be in the IndySDK implementation
kdenhartog Dec 11, 2018
215fe58
added future changes functionality
kdenhartog Dec 11, 2018
33d7a60
updated HIPE to match code and add algorithm for serializing
kdenhartog Jan 7, 2019
f9167c4
Merge branch 'master' into AMES
kdenhartog Jan 7, 2019
fd3d8cc
tweaked to clarify in response to telegramsam comments
kdenhartog Jan 7, 2019
d777fb2
Merge branch 'AMES' of github.com:kdenhartog/indy-hipe into AMES
kdenhartog Jan 7, 2019
c955e3a
Merge branch 'master' into AMES
kdenhartog Jan 7, 2019
0b09c02
added examples of json
kdenhartog Jan 8, 2019
06739e8
Merge branch 'AMES' of github.com:kdenhartog/indy-hipe into AMES
kdenhartog Jan 8, 2019
1db7d6e
added additional details to reflect @swcurran comments
kdenhartog Jan 11, 2019
ebc2339
aligned HIPE with final implementation
kdenhartog Jan 22, 2019
8e7dfd2
added recipient_verkey
kdenhartog Jan 23, 2019
9d135e2
updated unpack algorithm details
kdenhartog Jan 23, 2019
cc5fdb6
fix typo
kdenhartog Jan 23, 2019
f586b31
updated docs
kdenhartog Jan 23, 2019
bb55f79
added changes based on new comments
kdenhartog Jan 23, 2019
da6c1fc
Explain for non-Indy audience
dhh1128 Jan 25, 2019
36a92cc
Merge pull request #3 from dhh1128/ames
kdenhartog Jan 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
349 changes: 349 additions & 0 deletions text/0028-wire-message-format/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
- Name: Wire Level Messages (JWM/JWEs)
- Author: Kyle Den Hartog(kyle.denhartog@evernym.com), Stephen Curran (swcurran@gmail.com), Sam Curren (sam@sovrin.org), Mike Lodder (mike@sovrin.org)
- Start Date: 2018-07-10 (approximate, backdated)
- Feature Branch: https://github.com/kdenhartog/indy-sdk/tree/multiplex-rebase
- JIRA ticket: IS-1073

# HIPE 0028-wire-message-format
[summary]: #summary

There are two layers of messages that combine to enable **interoperable** self-sovereign agent-to-agent communication. At the highest level are [Agent Plaintext Messages](https://github.com/hyperledger/indy-hipe/tree/master/text/0026-agent-file-format#agent-plaintext-messages-ap) - messages sent between identities to accomplish some shared goal (e.g., establishing a connection, issuing a verifiable credential, sharing a chat). Agent Plaintext Messages are delivered via the second, lower layer of messaging - Wire. An [Agent Wire Message](https://github.com/hyperledger/indy-hipe/tree/master/text/0026-agent-file-format#agent-wire-messages-aw) is a wrapper (envelope) around a plaintext message to permit secure sending and routing. A plaintext message going from its sender to its receiver passes through many agents, and a wire message envelope is used for each hop of the journey.

This HIPE describes the wire format and the functions in Indy SDK that implement it.

# Motivation
[motivation]: #motivation

Wire messages use a standard format built on [JSON Web Encryption - RFC 7516](
https://tools.ietf.org/html/rfc7516). This format is not captive to Indy; it requires
no special Indy worldview or Indy dependencies to implement. Rather, it is a
general-purpose solution to the question of how to encrypt, decrypt, and route
messages as they pass over any transport(s). By documenting the format here, we
hope to provide a point of interoperability for developers of agents inside and
outside the Indy ecosystem.

We also document how Indy SDK implements its support for wire format through the
`pack()` and `unpack()` functions. For developers of Indy SDK, this is a sort of
design doc; for those who want to implement the format in other tech stacks, it
may be a useful reference.

## Tutorial
[tutorial]: #tutorial

## Assumptions

We assume that each sending agent knows:

- Its intended recipient.
- What encryption (if any) is appropriate.
- If encryption will be used, a public key of the receiving agent.
- The physical endpoint to use for the receiver, and the appropriate transport protocol (https, zmq, etc.).

The assumptions can be made because either the message is being sent to an agent within the sending agent's domain and so the sender knows the internal configuration of agents, or the message is being sent outside the sending agent's domain and interoperability requirements are in force to define the sending agent's behaviour.

## Example Scenario

The example of Alice and Bob's [sovereign domains](https://docs.google.com/document/d/1gfIz5TT0cNp2kxGMLFXr19x1uoZsruUe_0glHst2fZ8/edit#heading=h.pufsrf9ucjvv) is used for illustrative purposes in defining this HIPE.

![Example Domains: Alice and Bob](domains.jpg)

In the diagram above:

- Alice has
- 1 Edge agent - "1"
- 1 Routing agent - "2"
- 1 Domain Endpoint - "8"
- Bob has
- 3 Edge Agents - "4", "5" and "6"
- "6" is an Edge agent in the cloud, "4" and "5" are physical devices.
- 1 Routing agent - "3"
- 1 Domain Endpoint - "9"

For the purposes of this discussion we are defining the Wire Message agent message flow to be:

> 1 --> 2 --> 8 --> 9 --> 3 --> 4

However, that flow is just one of several that could match this configuration. What we know for sure is that:

- 1 is the Sender agent in this case and so must send the first or original message.
- 9 is the Domain Endpoint of Bob's domain and so must receive the message as a wire message
- 4 is the Receiver in this case and so must receive (and should be able to read) the first or original message.

## Wire Messages

A wire wessage is used to transport any plaintext message from one agent directly to another. In our example message flow above, there are five wire messages sent, one for each hop in the flow. The process to send a wire message consists of the following steps:

- Call the standard function `pack()` (implemented in the Indy-SDK) to wrap the plaintext message
- Send the wire message using the transport protocol defined by the receiving endpoint
- Receive the wire message
- Call the standard function `unpack()` to retrieve the plaintext message (and possibly its provenance) from the wire message

This is repeated with each hop, but the wire messages are nested, such that the plaintext is never visible until
it reaches its final recipient.

## Implementation

We will describe the pack and unpack algorithms, and their output, in terms of
Indy's initial implementation, which may evolve over time. Other implementations
could be built, but they would need to emit and consume similar inputs and
outputs.

The data structures emitted and consumed by these algorithms are described
in a formal [schema](schema.md).

### Authcrypt mode vs. Anoncrypt mode

When packing and unpacking are done in a way that the sender is anonymous,
we say that we are in __anoncrypt mode__. When the sender is revealed, we
are in __authcrypt mode__. Authcrypt mode reveals the sender *to the recipient
only*; it is not the same as a non-repudiable signature. See the [HIPE about
signing](https://github.com/hyperledger/indy-hipe/pull/79), and [this
discussion about the theory of non-repudiation](https://github.com/sovrin-foundation/protocol/blob/d1039cd793a801abdc5fdfdc25ef071778039075/janus/repudiation.md).

### Pack Message

#### pack_message() interface

packed_message = pack_message(wallet_handle, message, receiver_verkeys, sender_verkey)

#### pack_message() Params:
- wallet_handle: handle to the wallet that contains the sender's secrets.
- message: the message (plaintext, or nested wire message) as a string. If it's JSON object it should be in string format first
- receiver_verkeys: a list of recipient verkeys as string containing a JSON array
- sender_verkey: the sender's verkey as a string. This verkey is used to look up the sender's private key so the wallet can put supply it as input to the encryption algorithm. When an empty string ("") is passed in this parameter, anoncrypt mode is used

#### pack_message() return value (Authcrypt mode)
This is an example of an outputted message encrypting for two verkeys using Authcrypt.

```json
{
"protected": "eyJlbmMiOiJ4Y2hhY2hhMjBwb2x5MTMwNV9pZXRmIiwidHlwIjoiSldNLzEuMCIsImFsZyI6IkF1dGhjcnlwdCIsInJlY2lwaWVudHMiOlt7ImVuY3J5cHRlZF9rZXkiOiJMNVhEaEgxNVBtX3ZIeFNlcmFZOGVPVEc2UmZjRTJOUTNFVGVWQy03RWlEWnl6cFJKZDhGVzBhNnFlNEpmdUF6IiwiaGVhZGVyIjp7ImtpZCI6IkdKMVN6b1d6YXZRWWZOTDlYa2FKZHJRZWpmenRONFhxZHNpVjRjdDNMWEtMIiwiaXYiOiJhOEltaW5zdFhIaTU0X0otSmU1SVdsT2NOZ1N3RDlUQiIsInNlbmRlciI6ImZ0aW13aWlZUkc3clJRYlhnSjEzQzVhVEVRSXJzV0RJX2JzeERxaVdiVGxWU0tQbXc2NDE4dnozSG1NbGVsTThBdVNpS2xhTENtUkRJNHNERlNnWkljQVZYbzEzNFY4bzhsRm9WMUJkREk3ZmRLT1p6ckticUNpeEtKaz0ifX0seyJlbmNyeXB0ZWRfa2V5IjoiZUFNaUQ2R0RtT3R6UkVoSS1UVjA1X1JoaXBweThqd09BdTVELTJJZFZPSmdJOC1ON1FOU3VsWXlDb1dpRTE2WSIsImhlYWRlciI6eyJraWQiOiJIS1RBaVlNOGNFMmtLQzlLYU5NWkxZajRHUzh1V0NZTUJ4UDJpMVk5Mnp1bSIsIml2IjoiRDR0TnRIZDJyczY1RUdfQTRHQi1vMC05QmdMeERNZkgiLCJzZW5kZXIiOiJzSjdwaXU0VUR1TF9vMnBYYi1KX0pBcHhzYUZyeGlUbWdwWmpsdFdqWUZUVWlyNGI4TVdtRGR0enAwT25UZUhMSzltRnJoSDRHVkExd1Z0bm9rVUtvZ0NkTldIc2NhclFzY1FDUlBaREtyVzZib2Z0d0g4X0VZR1RMMFE9In19XX0=",
"iv": "ZqOrBZiA-RdFMhy2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why iv not called nonce as called in libsodium. I see indy-sdk code does not call it nonce either, is that the reason or something else?

"ciphertext": "K7KxkeYGtQpbi-gNuLObS8w724mIDP7IyGV_aN5AscnGumFd-SvBhW2WRIcOyHQmYa-wJX0MSGOJgc8FYw5UOQgtPAIMbSwVgq-8rF2hIniZMgdQBKxT_jGZS06kSHDy9UEYcDOswtoLgLp8YPU7HmScKHSpwYY3vPZQzgSS_n7Oa3o_jYiRKZF0Gemamue0e2iJ9xQIOPodsxLXxkPrvvdEIM0fJFrpbeuiKpMk",
"tag": "kAuPl8mwb0FFVyip1omEhQ=="
}
```

The protected data base64URL decodes to this:
```json
{
"enc": "xchacha20poly1305_ietf",
Copy link
Contributor

@lovesh lovesh Mar 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code we have in indy-sdk seems to be using xsalsa20 and not xchacha20? Is there a proposed change to xchacha20? Or does this enc refer to encryption method of the message and the method to encrypt will allways remain libsodium's crypto_box?

"typ": "JWM/1.0",
"alg": "Authcrypt",
"recipients": [
{
"encrypted_key": "L5XDhH15Pm_vHxSeraY8eOTG6RfcE2NQ3ETeVC-7EiDZyzpRJd8FW0a6qe4JfuAz",
"header": {
"kid": "GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL",
"iv": "a8IminstXHi54_J-Je5IWlOcNgSwD9TB",
"sender": "ftimwiiYRG7rRQbXgJ13C5aTEQIrsWDI_bsxDqiWbTlVSKPmw6418vz3HmMlelM8AuSiKlaLCmRDI4sDFSgZIcAVXo134V8o8lFoV1BdDI7fdKOZzrKbqCixKJk="
}
},
{
"encrypted_key": "eAMiD6GDmOtzREhI-TV05_Rhippy8jwOAu5D-2IdVOJgI8-N7QNSulYyCoWiE16Y",
"header": {
"kid": "HKTAiYM8cE2kKC9KaNMZLYj4GS8uWCYMBxP2i1Y92zum",
"iv": "D4tNtHd2rs65EG_A4GB-o0-9BgLxDMfH",
"sender": "sJ7piu4UDuL_o2pXb-J_JApxsaFrxiTmgpZjltWjYFTUir4b8MWmDdtzp0OnTeHLK9mFrhH4GVA1wVtnokUKogCdNWHscarQscQCRPZDKrW6boftwH8_EYGTL0Q="
}
}
]
}
```

#### pack output format (Authcrypt mode)

```
{
"protected": "b64URLencoded({
"enc": "xchachapoly1305_ietf",
"typ": "JWM/1.0",
"alg": "Authcrypt",
"recipients": [
{
"encrypted_key": base64URLencode(libsodium.crypto_box(my_key, their_vk, cek, cek_iv))
"header": {
"kid": "base58encode(recipient_verkey)",
"sender" : base64URLencode(libsodium.crypto_box_seal(their_vk, base58encode(sender_vk)),
"iv" : base64URLencode(cek_iv)
}
},
],
})",
"iv": <b64URLencode(iv)>,
"ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek),
"tag": <b64URLencode(tag)>
}
```

#### Authcrypt pack algorithm

1. generate a content encryption key (symmetrical encryption key)
2. encrypt the CEK for each recipient's public key using Authcrypt (steps below)
1. set `encrypted_key` value to base64URLencode(libsodium.crypto_box(my_key, their_vk, cek, cek_iv))
* Note it this step we're encrypting the cek, so it can be decrypted by the recipient
2. set `sender` value to base64URLencode(libsodium.crypto_box_seal(their_vk, sender_vk_string))
* Note in this step we're encrypting the sender_verkey to protect sender anonymity
3. base64URLencode(cek_iv) and set to `iv` value in the header
* Note the cek_iv in the header is used for the `encrypted_key` where as `iv` is for ciphertext
3. base64URLencode the `protected` value
4. encrypt the message using libsodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(message, protected_value_encoded, iv, cek) this is the ciphertext.
5. base64URLencode the iv, ciphertext, and tag then serialize the format into the output format listed above.

For a reference implementation, see https://github.com/hyperledger/indy-sdk/libindy/src/commands/crypto.rs

#### pack_message() return value (Anoncrypt mode)
This is an example of an outputted message encrypted for two verkeys using Anoncrypt.

```json
{
"protected": "eyJlbmMiOiJ4Y2hhY2hhMjBwb2x5MTMwNV9pZXRmIiwidHlwIjoiSldNLzEuMCIsImFsZyI6IkFub25jcnlwdCIsInJlY2lwaWVudHMiOlt7ImVuY3J5cHRlZF9rZXkiOiJYQ044VjU3UTF0Z2F1TFcxemdqMVdRWlEwV0RWMFF3eUVaRk5Od0Y2RG1pSTQ5Q0s1czU4ZHNWMGRfTlpLLVNNTnFlMGlGWGdYRnZIcG9jOGt1VmlTTV9LNWxycGJNU3RqN0NSUHNrdmJTOD0iLCJoZWFkZXIiOnsia2lkIjoiR0oxU3pvV3phdlFZZk5MOVhrYUpkclFlamZ6dE40WHFkc2lWNGN0M0xYS0wifX0seyJlbmNyeXB0ZWRfa2V5IjoiaG5PZUwwWTl4T3ZjeTVvRmd0ZDFSVm05ZDczLTB1R1dOSkN0RzRsS3N3dlljV3pTbkRsaGJidmppSFVDWDVtTU5ZdWxpbGdDTUZRdmt2clJEbkpJM0U2WmpPMXFSWnVDUXY0eVQtdzZvaUE9IiwiaGVhZGVyIjp7ImtpZCI6IjJHWG11Q04ySkN4U3FNUlZmdEJITHhWSktTTDViWHl6TThEc1B6R3FRb05qIn19XX0=",
"iv": "M1GneQLepxfDbios",
"ciphertext": "iOLSKIxqn_kCZ7Xo7iKQ9rjM4DYqWIM16_vUeb1XDsmFTKjmvjR0u2mWFA48ovX5yVtUd9YKx86rDVDLs1xgz91Q4VLt9dHMOfzqv5DwmAFbbc9Q5wHhFwBvutUx5-lDZJFzoMQHlSAGFSBrvuApDXXt8fs96IJv3PsL145Qt27WLu05nxhkzUZz8lXfERHwAC8FYAjfvN8Fy2UwXTVdHqAOyI5fdKqfvykGs6fV",
"tag": "gL-lfmD-MnNj9Pr6TfzgLA=="
}
```

The protected data decodes to this:

```json
{
"enc": "xchacha20poly1305_ietf",
"typ": "JWM/1.0",
"alg": "Anoncrypt",
"recipients": [
{
"encrypted_key": "XCN8V57Q1tgauLW1zgj1WQZQ0WDV0QwyEZFNNwF6DmiI49CK5s58dsV0d_NZK-SMNqe0iFXgXFvHpoc8kuViSM_K5lrpbMStj7CRPskvbS8=",
"header": {
"kid": "GJ1SzoWzavQYfNL9XkaJdrQejfztN4XqdsiV4ct3LXKL"
}
},
{
"encrypted_key": "hnOeL0Y9xOvcy5oFgtd1RVm9d73-0uGWNJCtG4lKswvYcWzSnDlhbbvjiHUCX5mMNYulilgCMFQvkvrRDnJI3E6ZjO1qRZuCQv4yT-w6oiA=",
"header": {
"kid": "2GXmuCN2JCxSqMRVftBHLxVJKSL5bXyzM8DsPzGqQoNj"
}
}
]
}
```

#### pack output format (Anoncrypt mode)
```
{
"protected": "b64URLencoded({
"enc": "xchachapoly1305_ietf",
"typ": "JWM/1.0",
"alg": "Anoncrypt",
"recipients": [
{
"encrypted_key": base64URLencode(libsodium.crypto_box_seal(their_vk, cek)),
"header": {
"kid": base58encode(recipient_verkey),
}
},
],
})",
"iv": b64URLencode(iv),
"ciphertext": b64URLencode(encrypt_detached({'@type'...}, protected_value_encoded, iv, cek),
"tag": b64URLencode(tag)
}
```

#### Anoncrypt pack algorithm

1. generate a content encryption key (symmetrical encryption key)
2. encrypt the CEK for each recipient's public key using Authcrypt (steps below)
1. set `encrypted_key` value to base64URLencode(libsodium.crypto_box_seal(their_vk, cek))
* Note it this step we're encrypting the cek, so it can be decrypted by the recipient
3. base64URLencode the `protected` value
4. encrypt the message using libsodium.crypto_aead_chacha20poly1305_ietf_encrypt_detached(message, protected_value_encoded, iv, cek) this is the ciphertext.
5. base64URLencode the iv, ciphertext, and tag then serialize the format into the output format listed above.

For a reference implementation, see https://github.com/hyperledger/indy-sdk/libindy/src/commands/crypto.rs

### Unpack Message

#### unpack_message() inteface

unpacked_message = unpack_message(wallet_handle, jwe)

#### unpack_message() Params

- wallet_handle: wallet handle that contains the sender_verkey
- jwe: a message which was returned from a pack_message() and follows the scheme format described below


#### Unpack Algorithm

1. seralize data, so it can be used
* For example, in rust-lang this has to be seralized as a struct.
2. Lookup the `kid` for each recipient in the wallet to see if the wallet possesses a private key associated with the public key listed
3. Check if a `sender` field is used.
* If a sender is included use auth_decrypt to decrypto the `encrypted_key` by doing the following:
1. decrypt sender verkey using libsodium.crypto_box_seal_open(my_private_key, base64URLdecode(sender))
2. decrypt cek using libsodium.crypto_box_open(my_private_key, sender_verkey, encrypted_key, cek_iv)
3. decrypt ciphertext using libsodium.crypto_aead_chacha20poly1305_ietf_open_detached(base64URLdecode(ciphertext_bytes), base64URLdecode(protected_data_as_bytes), base64URLdecode(nonce), cek)
4. return `message`, `recipient_verkey` and `sender_verkey` following the authcrypt format listed below
* If a sender is NOT included use a anon_decrypt to decrypt the `encrypted_key` by doing the following:
1. decrypt `encrypted_key` using libsodium.crypto_box_seal_open(my_private_key, encrypted_key)
2. decrypt ciphertext using libsodium.crypto_aead_chacha20poly1305_ietf_open_detached(base64URLdecode(ciphertext_bytes), base64URLdecode(protected_data_as_bytes), base64URLdecode(nonce), cek)
3. 4. return `message` and `recipient_verkey` following the anoncrypt format listed below



For a reference implementation, see https://github.com/hyperledger/indy-sdk/libindy/src/commands/crypto.rs

#### unpack_message() return values (authcrypt mode)

```json
{
"message": "{ \"@id\": \"123456780\",\"@type\":\"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message\",\"sent_time\": \"2019-01-15 18:42:01Z\",\"content\": \"Your hovercraft is full of eels.\"}",
"recipient_verkey": "HKTAiYM8cE2kKC9KaNMZLYj4GS8uWCYMBxP2i1Y92zum",
"sender_verkey": "DWwLsbKCRAbYtfYnQNmzfKV7ofVhMBi6T4o3d2SCxVuX"
}
```

#### unpack_message() return values (anoncrypt mode)
```json
{
"message": "{ \"@id\": \"123456780\",\"@type\":\"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/basicmessage/1.0/message\",\"sent_time\": \"2019-01-15 18:42:01Z\",\"content\": \"Your hovercraft is full of eels.\"}",
"recipient_verkey": "2GXmuCN2JCxSqMRVftBHLxVJKSL5bXyzM8DsPzGqQoNj"
}
```

# Additional Notes
[additional-notes]: #additional-notes

* All `kid` values used currently are base58 encoded ed25519 keys. If other keys types are used, say secp256k1, base58 encoding should also be used here for interoperability.

* All algorithm APIs which use libsodium are from [sodiumoxide](https://crates.io/crates/sodiumoxide) rust wrapping of the original C implementation.

# Drawbacks
[drawbacks]: #drawbacks

The current implementation of the `pack()` message is currently Hyperledger Indy specific. It is based on common crypto libraries ([NaCl](https://nacl.cr.yp.to/)), but the wrappers are not commonly used outside of Indy. There's currently work being done to fine alignment on a cross-ecosystem interopable protocol, but this hasn't been achieved yet. This work will hopefully bridge this gap.



# Rationale and alternatives
[alternatives]: #alternatives

As the [JWE](https://tools.ietf.org/html/rfc7516) standard currently stands, it does not follow this format. We're actively working with the lead writer of the JWE spec to find alignment and are hopeful the changes needed can be added.
kdenhartog marked this conversation as resolved.
Show resolved Hide resolved

We've also looked at using the [Message Layer Security (MLS) specification](https://datatracker.ietf.org/wg/mls/about/). This specification shows promise for adoption later on with more maturity. Additionally because they aren't hiding metadata related to the sender (Sender Anonymity), we would need to see some changes made to the specification before we could adopt this spec.

# Prior art
[prior-art]: #prior-art

The [JWE](https://tools.ietf.org/html/rfc7516) family of encryption methods.

# Unresolved questions
[unresolved]: #unresolved-questions

- How transport protocols (https, zmq, etc.) will be be used to send Wire Messages?
- These will need to be defined using seperate HIPEs. For example, HTTP might POST a message and place it in the body of the HTTP POST.
- How will the wire messages work with routing tables to pass a message through a domain, potentially over various transport protocols?
- There's not much certainty whether routing tables or some other mechanism will be used. This needs to be defined in another HIPE.
- If the wire protocol fails, how is that failure passed back to those involved in the transmission?
- This should be handled using the error-reporting mechanism which is currently proposed HIPE #65 by Stephen Curran.
Binary file added text/0028-wire-message-format/domains.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading