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

CIP-0020 | Update with new Implementors, Screenshots ... #394

Merged
merged 35 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
942e121
Create cip0020-encryption-modes.json
gitmachtl Nov 29, 2022
61b0ac5
Update cip0020-encryption-modes.json
gitmachtl Nov 29, 2022
2afea02
Update README.md
gitmachtl Nov 29, 2022
8639330
Update README.md
gitmachtl Nov 29, 2022
aabfacd
Update README.md
gitmachtl Nov 29, 2022
f6db60a
Create demo_via_nodeJS.js
gitmachtl Nov 29, 2022
c7acbd3
Create demo_via_PHP.php
gitmachtl Nov 29, 2022
0050d55
Update demo_via_nodeJS.js
gitmachtl Nov 29, 2022
7b9290f
Update README.md
gitmachtl Nov 29, 2022
0553507
Update README.md
gitmachtl Nov 29, 2022
199a8f5
Update README.md
gitmachtl Nov 29, 2022
6f877ce
Create cip0020-democode-PHP.php
gitmachtl Nov 29, 2022
30f59f9
Delete demo_via_PHP.php
gitmachtl Nov 29, 2022
9e3b746
Create cip0020-democode-NODEJS.js
gitmachtl Nov 29, 2022
629e355
Delete demo_via_nodeJS.js
gitmachtl Nov 29, 2022
b6bf2b3
Create normal-message-metadata.json
gitmachtl Nov 29, 2022
02cbc5c
Create encrypted-message-metadata.json
gitmachtl Nov 29, 2022
400fdb5
Create cip0020-democode-BASH.sh
gitmachtl Nov 29, 2022
cb63808
Update cip0020-democode-BASH.sh
gitmachtl Nov 29, 2022
5c593ba
Update README.md
gitmachtl Nov 29, 2022
fe27b14
Update README.md
gitmachtl Nov 29, 2022
7dd544c
Update README.md
gitmachtl Nov 29, 2022
5e95677
Update README.md
gitmachtl Nov 29, 2022
b29186c
Update README.md
gitmachtl Nov 29, 2022
8ad5e42
Update README.md
gitmachtl Nov 29, 2022
24d892f
Update README.md
gitmachtl Nov 29, 2022
b9672fe
Added 'SPO Scripts' as an encrypted msg integration example
gitmachtl Dec 3, 2022
6441cd3
Delete cip0020-encryption-modes.json
gitmachtl Dec 8, 2022
85f8fa7
Delete cip0020-democode-BASH.sh
gitmachtl Dec 8, 2022
dd923ce
Delete cip0020-democode-NODEJS.js
gitmachtl Dec 8, 2022
ccfcb02
Delete cip0020-democode-PHP.php
gitmachtl Dec 8, 2022
cc10ca9
Delete encrypted-message-metadata.json
gitmachtl Dec 8, 2022
0a246ef
Delete normal-message-metadata.json
gitmachtl Dec 8, 2022
768080b
Updating README with updated Implementors
gitmachtl Dec 8, 2022
4e9a0cd
Adjust authors list (remove markdown) + adjust section titles levels.
KtorZ Dec 8, 2022
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
204 changes: 182 additions & 22 deletions CIP-0020/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
CIP: 20
Title: Transaction message/comment metadata
Authors: Martin Lang <martin@martinlang.at>, Ola Ahlman <ola@ahlnet.nu>, Andrew Westberg <andrewwestberg@gmail.com>
Authors: Martin Lang <martin@martinlang.at>, Ola Ahlman <ola@ahlnet.nu>, Andrew Westberg <andrewwestberg@gmail.com>, Adam Dean <adam@crypto2099.io>
Comments-URI: no comments yet
Status: Active
Type: Informational
Created: 2021-06-13
Updated: 2022-11-29
License: CC-BY-4.0
---

Expand All @@ -20,15 +21,23 @@ We have the utilities on the cardano blockchain now since the introduction of th
So the CIP authors came together to form a first implementation of this. It is straight and simple, additional keys and content can be added later.
The IOG main wallet `Daedalus` can now also directly show attached metadata information in the transaction details view. This CIP is the missing link to bring it together.

Current Tools/Sites/Explorers that have implemented it already or have plans to implement it:
Some of the current Tools/Sites/Explorers that have implemented it already:
gitmachtl marked this conversation as resolved.
Show resolved Hide resolved
* [CNTools](https://cardano-community.github.io/guild-operators/#/Scripts/cntools)
* [JorManager](https://bitbucket.org/muamw10/jormanager/)
* [StakePoolOperator Scripts](https://github.com/gitmachtl/scripts)
* [Cardanoscan.io](https://cardanoscan.io)
* [AdaStat.net](https://adastat.net)
* [CardanoCommunityWallet](https://ccwallet.io)
* [Eternl Wallet](https://eternl.io)
* [CardanoWall](https://cardanowall.com)
* [Nami Wallet](https://namiwallet.io)
* [CNFT](https://cnft.io)
* [Cardano Explorer](https://cexplorer.io)
* [SundaeSwap](https://https://sundaeswap.finance/)
* [Minswap](https://minswap.org/)
* [MuesliSwap](https://muesliswap.com/)
* [DripDropz.io](https://dripdropz.io/)
* [Typhon Wallet](https://typhonwallet.io/)
* [Ledger Live](https://www.ledger.com/)

# Specification

Expand All @@ -37,37 +46,38 @@ The used metadatum label is **`"674":`**, this number was choosen because it is
The message content has the key **`"msg":`** and consists of an **array** of individual **message-strings**.
The number of theses **message-strings** must be at least one for a single message, more for multiple messages/lines. Each of theses individual **message-strings** array entries must be at most 64 bytes when UTF-8 encoded.

Format:
### Format:
```
{
"674":
{ "msg":
{
"msg":
[
"message-string 1" //Optional: ,"message-string 2","message-string 3" ...
]
}
}
```



Example for a single message/comment/memo:
### Example for a single message/comment/memo:
``` json
{
"674":
{ "msg":
{
"msg":
[
"This is a comment for the transaction xyz, thank you very much!"
]
}
}
```

Example for multiple messages/comments/memos:
### Example for multiple messages/comments/memos:
``` json
{
"674":
{ "msg":
{
"msg":
[
"Invoice-No: 1234567890",
"Customer-No: 555-1234",
Expand All @@ -76,35 +86,185 @@ Example for multiple messages/comments/memos:
}
}
```
Example above in **Daedalus** currently (could be improved if CIP is implemented):
![image](https://user-images.githubusercontent.com/47434720/121822100-85b38a80-cc9d-11eb-9d13-1869746a69b2.png)

## Some Integration examples
&nbsp;<p>

# Specification - Encrypted message

This is an addition to the original CIP-0020, which is active since mid 2021 and widely used across many entities. It is fully backwards compatible and requires no changes in existing tools, explorers, wallets.

Why do we need this? Metadata is sent unencrypted and in plaintext over the networks, a 3rd-party or man-in-the-middle can easily collect data such as bank-account-numbers, email-addresses, etc. out of such messages. With even a simple encryption of such a message - and publicly known passphrase - it is much more complicated for the man-in-the-middle listener to collect data on the fly.

The specification update for encrypted messages takes advantage of the simple original design, which is leaving room for additional json-keys not affecting the parsing of the content at all. The only outcome if a receiver does not process the encrypted content is, that the encrypted message is shown instead of an maybe autodecrypted one. But even the encrypted base64 strings fit into the max. 64char long string restriction. So it does not break any tools. More on the autodecryption later.

### Format:
```
{
"674":
{
"enc": "<encryptionmode>",
"msg":
[
"base64-string 1", "base64-string 2", "base64-string 3" ...
]
}
}
```
The format is identical to the normal one, with a simple addition of the `enc` (encryptionmode) entry.

The value given in the `enc` field references an entry in the [Encryption Mode Json](cip0020-encryption-modes.json) file, which collects different encryption methods and there parameters. Starting with a simple implementation named `basic`. This reference file is just a collection and should be seen as a look-up-file about the methods. This file can also be updated and extended with new encryption methods - like with public/private key encryption - easily in future updates.

&nbsp;<p>

### Encryption modes:

* **plain** - no encryption at all
``` json
"plain": {
"desc": "plaintext, no encryption" }
```
This is not really an encryption mode, but included as a backwards compatible entry to signal this message as an unencrypted one. The entry is not needed and fully optional for unencrypted messages.

* **basic** - aes-256-cbc salted symmetric encryption via passpharse (+default passphrase)

Lets list the entry from the [Encryption Mode Json](cip0020-encryption-modes.json) file first for the `basic` method:
``` json
"basic": {
"desc": "symmetrical encryption via openssl and a passphrase (default=cardano)",
"type": "openssl",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not super convinced by this format. I think if you try to go down this route, this is what will happen:

  1. At some point, people will start asking for other encryption schemes and you will keep modifying this list and it will get bigger
  2. At some point, somebody will suggest that instead of specifying some totally custom format for this, you should just standardize it to something like https://github.com/panva/jose so that you automatically get SDKs for a bunch of langauges, etc.
  3. Somebody will point out that instead of using a JSON-based SDK, you should use a CBOR-based standard since that's what Cardano is actually storing on-chain
  4. You will realize that the Cardano message signing spec is actually already meant to handle mostly (3)

so if you actually want to do this route, it may make more sense to make a separate CIP from CIP20 that talks about how to take the message signing spec and building some metadata standard that uses it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @SebastienGllmt thx for the feedback!

The current format of this "lookup" file was choosen as a simple first start. It was not intended to be compatible for all possible future updates with all kinds of different encryption types. It could also be a simple text description file. It is ment currently as a place to collect the key parameters.

I agree that CIP8 has some elements in it, but is to complicated to act as an easy upgrade to the existing transaction message/memo/comment format imo. When we started with CIP-0020 the intention was to keep it simple so many can implement it, but also leave it open enough to upgrade it. For the CIP8 style encryption, its ChachaPoly instead of AES256 for the method via passphrase. But CIP8 is oriented in signing in first place. Going with this format would make it totally incompatible with the current CIP-0020 format.

Let me think about it...

Copy link
Contributor

Choose a reason for hiding this comment

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

What I like about this update is the simplicity of implementing openssl encryption for wallets. This isn't designed to be the end-all-be-all security solution for privacy on the blockchain. There's better options and upcoming Midnight for that. This is just so your receipt for a purchase at seedywebsite.com isn't in cleartext for everyone to see.

"cipher": "aes-256-cbc",
"digest": "pdkdf2",
"iter": 10000,
"encode": "base64" }
```

OpenSSL was choosen, because its fast and widely available also for all kind of different platforms, web frontends, etc. Encryption algo is **AES-256-CBC** (salted) using `pdkdf2` to derive the key from the given passphrase. 10000 Iterations is the default value for this encryption method. The format of the encoded output is base64 format.

The encryption is based on a given passphrase, which can be choosen by the user. However, a default-passphrase "cardano" should be used to encrypt/decrypt if no other passphrase is provided or known.

Why a default passphrase?

As pointed out above, its way harder for man-in-the-middle listeners, to decrypt every single message on the fly. So by using a default passphrase, tools can encrypt messages and explorers/wallets can autodecrypt such messages trying to use the default passphrase. In that way, the displayed message is automatically readable to the user. If a more protected communication is needed, the sender can choose a custom passphrase and communicate that to the receiver as a preshared passphrase.

What part is uses for the encryption?

The **whole content** of the unencrypted normal transaction **metadata `msg:` key is used**, thats the array with the message string(s). (Example below)

Is there sample code?

Yes, example implementations for node.js, PHP, bash, etc. can be found in the [codesamples](codesamples/) folder. They are showing how to encrypt/decrypt text with the right parameters set for this basic mode.

:warning: **Message decryption should be done on the user frontend if possible, not via server callbacks.**

&nbsp;<p>

### Encryption/Decryption example on the console - basic mode

First, generate a normal metadata transaction message.

**normal-message-metadata.json**:
``` json
{
"674": {
"msg": ["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]
}
}
```

The **encryption** is done on the **whole content of the `msg:` key**, so this is

`["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]`

in our example.

**Encrypt** this content via openssl, the default passprase **cardano**, iteration set to 10000 and key-derivation via pbkdf2:
``` console
openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano" <<< '["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]'
```

The encrypted result are the **base64 encoded strings**:
```
U2FsdGVkX1/5Y0A7l8xK686rvLsmPviTlna2n3P/ADNm89Ynr1UPZ/Q6bynbe28Y
/zWYOB9PAGt+bq1L0z/W2LNHe92HTN/Fwz16aHa98TOsgM3q8tAR4NSqrLZVu1H7
```

Compose the JSON by **using the base64 encoded encrypted strings now for the `msg:` part**.

Also add the value `basic` for the `enc:` key, to mark this transaction message as encrypted with basic mode.

**encrypted-message-metadata.json**:
``` json
{
"674":
{
"enc": "basic",
"msg":
[
"U2FsdGVkX1/5Y0A7l8xK686rvLsmPviTlna2n3P/ADNm89Ynr1UPZ/Q6bynbe28Y",
"/zWYOB9PAGt+bq1L0z/W2LNHe92HTN/Fwz16aHa98TOsgM3q8tAR4NSqrLZVu1H7"
]
}
}
```

Console one-liner:
``` console
jq ".\"674\".msg = [ $(jq -crM .\"674\".msg normal-message-metadata.json | openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano" | awk {'print "\""$1"\","'} | sed '$ s/.$//') ]" <<< '{"674":{"enc":"basic"}}' | tee encrypted-message-metadata.json | jq
```

---

A **decryption** can be done in a similar way:
``` console
jq -crM ".\"674\".msg[]" encrypted-message-metadata.json | openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano"
```

Which results in the original content of the **msg** key:

`["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]`

&nbsp;<p>

## Some Integration examples (standard/unencrypted)

**Ledger Live** is offering a memo field
![image](https://user-images.githubusercontent.com/47434720/204649383-c34ae733-e136-41b8-8fa8-619dde978621.png)

**Daedalus** shows the metadata text (could be improved if CIP is implemented):
![image](https://user-images.githubusercontent.com/47434720/121822100-85b38a80-cc9d-11eb-9d13-1869746a69b2.png)

**Cardanoscan.io**, **Adastat.net** and other tools implemented it already, to show messages along transactions:
![image](https://user-images.githubusercontent.com/47434720/124379245-1f2af680-dcb6-11eb-97b7-10f70d840e88.png)
![image](https://user-images.githubusercontent.com/47434720/124381343-3ff94900-dcc2-11eb-8d03-8fbacd3322b0.png)
![image](https://user-images.githubusercontent.com/47434720/204633595-d865c7ee-0c30-4af1-bb55-3c0ad323b58c.png)
![image](https://user-images.githubusercontent.com/47434720/204634111-256c6c18-974a-41f5-a6e4-b9edee8f9d62.png)

**ccwallet.io** has added it with a message field on the sending-page, and shows it also on the transactions-page:
![image](https://user-images.githubusercontent.com/47434720/127367420-b360972d-c6e0-4002-865e-df070904bd30.png)
![image](https://user-images.githubusercontent.com/47434720/127367228-339ac059-007a-40fd-a6c0-97f890e93964.png)
![image](https://user-images.githubusercontent.com/47434720/127368912-c85dc9f0-6ee3-4cc1-a24b-9716a20f27d3.png)
**eternl.io** has added it with a message field on the sending-page, and shows it also on the transactions-page:
![image](https://user-images.githubusercontent.com/47434720/204632224-5be33098-00f6-41da-a2f0-7c138b28354f.png)
![image](https://user-images.githubusercontent.com/47434720/204632802-33f1afa5-d9b2-494f-84fe-d7f0594a7f1b.png)

**StakePool Operator Tools**: It works on the commandline like any other script of the collection by just adding the "msg: ..." parameter to a transaction. This automatically generates the needed metadata.json structure and attaches it to the transaction itself.
**StakePool Operator Scripts**: It works on the commandline like any other script of the collection by just adding the "msg: ..." parameter to a transaction. This automatically generates the needed metadata.json structure and attaches it to the transaction itself.
![image](https://user-images.githubusercontent.com/47434720/129110626-6bc5b3c3-102d-4793-b508-7d4190b31cf7.png)

**CNTools**:<br>
![image](https://user-images.githubusercontent.com/47434720/130353491-fc0f3a69-1937-4e72-b680-c04cc069b5c4.png)

## Integration examples for encrypted messages

**Cexplorer.io**: With the implementation of the **encrypted message decoding**.
![image](https://user-images.githubusercontent.com/47434720/204560392-f45bbe4f-7f78-48fa-9e47-4d3b104685bf.png)

**StakePool Operator Scripts**: It works on the commandline like any other script of the collection by just adding the `"enc: basic"` parameter, you can provide an individual passphrase by using the `"pass:<passphrase>"` parameter. This automatically generates the needed metadata.json structure with the encrypted message in it and attaches it to the transaction itself.
![image](https://user-images.githubusercontent.com/47434720/205442737-748a7fb0-90fc-4cc3-898c-98b06894a900.png)

# Rationale

This design is simple, so many tools on the cardano blockchain can implement it easily. The array type was choosen to have consistency, no need to switch between a string or
an array format, or testing against a string or array format. Updates in the future are possible, like adding a versioning key `"ver":`, adding a key `"utxo":` to provide specific data for every tx-out#idx in the transaction, making subarrays in the message-strings, etc. But for now, we need a common agreement to provide general messages/comments/memos with this CIP. The starting design war choosen as simple as possible to keep the additional transaction fees as low as possible.
an array format, or testing against a string or array format. Updates in the future are possible, like adding a versioning key `"ver":`, adding a key `"utxo":` to provide specific data for every tx-out#idx in the transaction, adding the `"enc":` key like for encrypted messages, making subarrays in the message-strings, etc. But for now, we need a common agreement to provide general messages/comments/memos with this CIP. The starting design war choosen as simple as possible to keep the additional transaction fees as low as possible.

## Wallet Implementation

Would be a good idea to hide the message/comment/note behind a "show unmoderated content" button/drop-down. Like the Metadata display on the Cardano Explorer. Also, it should be displayed as plain-text non-clickable. To enhance security further, URLs could be automatically deleted or hidden from such comments, to not welcome bad actors with phishing attempts. Another solution to start with would be to really limit the character space for display in Wallets, like limiting it to `a-zA-z0-9` and a handful of special chars like `+-_#()[]:` without a `.<>"/\` chars, so a domain or html code would not work. Last points are worth for discussions of course, because it would also filter out unicode.

> Additionally for encrypted messages: Wallets/Tools can implement an autodecryption attempt with the default passphrase on such messages, to give the user a more streamlined experience. Or they can prompt for an input and decrypt it once the user has requested it for further security.

## Handling ill-formed 674 metadata ##

Expand Down
13 changes: 13 additions & 0 deletions CIP-0020/cip0020-encryption-modes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"plain": {
"desc": "plaintext, no encryption"
},
"basic": {
"desc": "symmetrical encryption via openssl and a passphrase (default=cardano)",
"type": "openssl",
"cipher": "aes-256-cbc",
"digest": "pdkdf2",
"iter": 10000,
"encode": "base64"
}
}
50 changes: 50 additions & 0 deletions CIP-0020/codesamples/cip0020-democode-BASH.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash

# --------------------------------------------------------------------------------------------
# Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via BASH
# --------------------------------------------------------------------------------------------

#Setting default passphrase
passphrase="cardano"


#Unencrypted Metadata JSON
echo "Normal unencrpted messages metadata JSON:"
cat normal-message-metadata.json | jq
echo


#Encrypt the msg array from the JSON
encrText=$(jq -crM .\"674\".msg normal-message-metadata.json | openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "${passphrase}")
echo "Encrypted Strings (base64 format):"
echo "${encrText}"
echo


#Compose it into a new JSON and add the 'enc' entry
echo "New encrypted messages metadata JSON:"
jq ".\"674\".msg = [ $(awk {'print "\""$1"\","'} <<< ${encrText} | sed '$ s/.$//') ]" <<< '{"674":{"enc":"basic"}}' | jq


echo
echo "----------------------"
echo


#Encrypted Metadata JSON
echo "Encrypted messages metadata JSON:"
cat encrypted-message-metadata.json | jq
echo


#Decrypt the msg array from the JSON
decrText=$(jq -crM ".\"674\".msg[]" encrypted-message-metadata.json | openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 -a -k "${passphrase}")
echo "Decrypted Content:"
echo "${decrText}"
echo


#Compose it into a new JSON in the standard message format
echo "New messages metadata JSON:"
jq ".\"674\".msg = ${decrText}" <<< "{}"
echo
Loading