From 942e12122fbb8fd2e97f25dc919a25a416daa677 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 13:53:10 +0100 Subject: [PATCH 01/35] Create cip0020-encryption-modes.json --- CIP-0020/cip0020-encryption-modes.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 CIP-0020/cip0020-encryption-modes.json diff --git a/CIP-0020/cip0020-encryption-modes.json b/CIP-0020/cip0020-encryption-modes.json new file mode 100644 index 0000000000..a6a6dd8fc9 --- /dev/null +++ b/CIP-0020/cip0020-encryption-modes.json @@ -0,0 +1,13 @@ +{ + "plaintext": { + "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" + } +} From 61b0ac57c43af69244701cb6b2fd2a407ae93500 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 14:15:23 +0100 Subject: [PATCH 02/35] Update cip0020-encryption-modes.json --- CIP-0020/cip0020-encryption-modes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0020/cip0020-encryption-modes.json b/CIP-0020/cip0020-encryption-modes.json index a6a6dd8fc9..2474cfc231 100644 --- a/CIP-0020/cip0020-encryption-modes.json +++ b/CIP-0020/cip0020-encryption-modes.json @@ -1,5 +1,5 @@ { - "plaintext": { + "plain": { "desc": "plaintext, no encryption" }, "basic": { From 2afea02b7153c03d5a6b639171c909b9bb2a8229 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:27:18 +0100 Subject: [PATCH 03/35] Update README.md --- CIP-0020/README.md | 127 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 12 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index ca70386cf8..b9eef1ce6a 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -6,6 +6,7 @@ Comments-URI: no comments yet Status: Active Type: Informational Created: 2021-06-13 +Updated: 2022-11-29 License: CC-BY-4.0 --- @@ -30,18 +31,19 @@ Current Tools/Sites/Explorers that have implemented it already or have plans to * [CardanoWall](https://cardanowall.com) * [CNFT](https://cnft.io) -# Specification +# Specification - Original - Non encrypted message The specification for the individual strings follow the general design specification for JSON metadata, which is already implemented and in operation on the cardano blockchain. The used metadatum label is **`"674":`**, this number was choosen because it is the T9 encoding of the string "msg". 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" ... ] @@ -49,13 +51,12 @@ Format: } ``` - - -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!" ] @@ -63,11 +64,12 @@ Example for a single message/comment/memo: } ``` -Example for multiple messages/comments/memos: +### Example for multiple messages/comments/memos: ``` json { "674": - { "msg": + { + "msg": [ "Invoice-No: 1234567890", "Customer-No: 555-1234", @@ -76,10 +78,111 @@ 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 +# 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 passphrasw - 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 istead of an maybe autodecrypted one. More on the autodecryption later. + +### Format: +``` +{ + "674": + { + "enc": "", + "msg": + [ + "encrypted-string 1" //Optional: ,"encrypted-string 2","encyrpted-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. + +### Encryption modes: + +* **plain** - no encryption at all + +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 based 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", + "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. + +The part that is encrypted/decrypted is the value of the **msg** key from a normal transaction metadata json, the array with the message(s) string(s). + +Example implementations for node.js, PHP, etc. can be found in the [codesamples](codesamples/) folder. + +### Encryption/Decryption example on the console - basic + +First, generate a normal metadata transaction message. There is no difference yet. + +**normal-message-metadata.json**: +``` json +{ + "674": { + "msg": ["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"] + } +} +``` + +Encrypt the message via openssl and the default passprase **cardano**: +``` console +openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano" <<< '["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]' +``` + +Result is the base64 encoded encrypted text: +``` +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. + +**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 +``` + + + +# Some Integration examples + +**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) From 863933025966bb6ad7ec49e2e13b13fde9514a1f Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:45:30 +0100 Subject: [PATCH 04/35] Update README.md --- CIP-0020/README.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index b9eef1ce6a..2b0d70187e 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -31,7 +31,7 @@ Current Tools/Sites/Explorers that have implemented it already or have plans to * [CardanoWall](https://cardanowall.com) * [CNFT](https://cnft.io) -# Specification - Original - Non encrypted message +# Specification The specification for the individual strings follow the general design specification for JSON metadata, which is already implemented and in operation on the cardano blockchain. The used metadatum label is **`"674":`**, this number was choosen because it is the T9 encoding of the string "msg". @@ -79,6 +79,8 @@ The number of theses **message-strings** must be at least one for a single messa } ``` + 

+ # 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. @@ -131,7 +133,7 @@ The part that is encrypted/decrypted is the value of the **msg** key from a norm Example implementations for node.js, PHP, etc. can be found in the [codesamples](codesamples/) folder. -### Encryption/Decryption example on the console - basic +### Encryption/Decryption example on the console - basic mode First, generate a normal metadata transaction message. There is no difference yet. @@ -149,7 +151,7 @@ Encrypt the message via openssl and the default passprase **cardano**: openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano" <<< '["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]' ``` -Result is the base64 encoded encrypted text: +Result are the base64 encoded strings: ``` U2FsdGVkX1/5Y0A7l8xK686rvLsmPviTlna2n3P/ADNm89Ynr1UPZ/Q6bynbe28Y /zWYOB9PAGt+bq1L0z/W2LNHe92HTN/Fwz16aHa98TOsgM3q8tAR4NSqrLZVu1H7 @@ -177,7 +179,17 @@ Console one-liner: 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"]` + 

# Some Integration examples @@ -199,7 +211,6 @@ jq ".\"674\".msg = [ $(jq -crM .\"674\".msg normal-message-metadata.json | opens **CNTools**:
![image](https://user-images.githubusercontent.com/47434720/130353491-fc0f3a69-1937-4e72-b680-c04cc069b5c4.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 From aabfacd75d9b4225a8819d3723da1a946975f4a3 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:47:31 +0100 Subject: [PATCH 05/35] Update README.md --- CIP-0020/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 2b0d70187e..89861c8d7d 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -211,6 +211,10 @@ Which results in the original content of the **msg** key: **CNTools**:
![image](https://user-images.githubusercontent.com/47434720/130353491-fc0f3a69-1937-4e72-b680-c04cc069b5c4.png) +**Cexplorer.io**: With the implementation of the **encrypted message decoding**. +![image](https://user-images.githubusercontent.com/47434720/204560392-f45bbe4f-7f78-48fa-9e47-4d3b104685bf.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 From f6db60adbd69ea711030ffb215f8fdaaf03754f0 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:53:36 +0100 Subject: [PATCH 06/35] Create demo_via_nodeJS.js --- CIP-0020/codesamples/demo_via_nodeJS.js | 97 +++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 CIP-0020/codesamples/demo_via_nodeJS.js diff --git a/CIP-0020/codesamples/demo_via_nodeJS.js b/CIP-0020/codesamples/demo_via_nodeJS.js new file mode 100644 index 0000000000..5efde7bbcf --- /dev/null +++ b/CIP-0020/codesamples/demo_via_nodeJS.js @@ -0,0 +1,97 @@ +// ---------------------------------------------------------------------------------------------- +// Demonstation implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE.JS +// ---------------------------------------------------------------------------------------------- + +const crypto = require('crypto'); + +// +// Calculate the KeyIV via the PasswordBasedKeyDerivedFormat2 pbkdf2 method, 10000 iterations, 48 bytes long, sha256 +// +function calc_KeyIV(passphrase, salt) { //passphrase as utf8 string, salt as hexstring + const key_IV = crypto.pbkdf2Sync(Buffer.from(passphrase,'utf8'), Buffer.from(salt,'hex'), 10000, 48, 'sha256').toString('hex') + console.log(` keyIV: ${key_IV}`); + return key_IV; //hex-string +} + +// +// Encryption Function +// +function encryptCardanoMessage(decrypted_msg, passphrase = 'cardano') { //decrypted_msg as utf8 string, passphrase as utf8 string(defaults to cardano) + //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext + //Build up the encrypted Message as hex string + var encrypted_hex = Buffer.from('Salted__','utf8').toString('hex'); + //Generate the random salt + var salt = crypto.randomBytes(8).toString('hex'); + encrypted_hex += salt; //append the salt + console.log(` salt: ${salt}`); + //Calculate the Key+IV + var keyIV = calc_KeyIV(passphrase, salt) + //The key itself is the first 32 Bytes (char 0-64 in hex string) + var key = keyIV.substring(0,64); + //The IV (initialization vector) is 16 Bytes and follows the key + var iv = keyIV.substring(64); + console.log(` key: ${key}`); + console.log(` iv: ${iv}`); + //Encrypt the message + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); + try { + var cyphertext = cipher.update(decrypted_msg, 'utf8', 'hex') + cipher.final('hex'); + } catch (error) { console.error(`Could not encrypt the message\n${error}`); process.exit(1); } + console.log(` cyphertext: ${cyphertext}`); + encrypted_hex += cyphertext; //append the cyphertext + console.log(` Enc-Message(hex): ${encrypted_hex}`); + return Buffer.from(encrypted_hex,'hex').toString('base64'); //base64 string +} + + +// +// Decryption Function +// +function decryptCardanoMessage(encrypted_msg, passphrase = 'cardano') { //encrypted_msg as base64 string, passphrase as utf8 string(defaults to cardano) + //Encrypted Message is base64 encoded, convert it to hex + const encrypted_hex = Buffer.from(encrypted_msg, 'base64').toString('hex'); + console.log(` Enc-Message(hex): ${encrypted_hex}`); + //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext + //Salt is byte 9-16 in the Encrypted Message (char 16-32 in a hex string) + var salt = encrypted_hex.substring(16,32); + console.log(` salt: ${salt}`); + //Cyphertext is all the rest after the salt (starting with char 32 in a hex string) + var cyphertext = encrypted_hex.substring(32); + console.log(` cyphertext: ${cyphertext}`); + //Calculate the Key+IV + var keyIV = calc_KeyIV(passphrase, salt) + //The key itself is the first 32 Bytes (char 0-64 in hex string) + var key = keyIV.substring(0,64); + //The IV (initialization vector) is 16 Bytes and follows the key + var iv = keyIV.substring(64); + console.log(` key: ${key}`); + console.log(` iv: ${iv}`); + //Decrypt the cyphertext with the key and the iv + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); + try { + var decr_msg = decipher.update(cyphertext, 'hex').toString('utf8') + decipher.final('utf8'); + } catch (error) { console.error(`Could not decrypt the message\n${error}`); process.exit(1); } + return decr_msg; //utf8 +} + +//------------------------- +// DEMO Encrypt and Decrypt +//------------------------- + +const passphrase = 'cardano'; //Using default passphrase 'cardano' + +// Encryption +console.log(`--- Encryption ---`); +var decrypted_msg = 'Hi, this is a test-message. Best regards, Martin'; +console.log(` Dec-Message(utf8): ${decrypted_msg}`) +var encrypted_msg = encryptCardanoMessage(decrypted_msg, passphrase); +console.log(`Enc-Message(base64): ${encrypted_msg}`); +console.log(`\n\n`); + +// Decryption +console.log(`--- Decryption ---`); +var encrypted_msg = 'U2FsdGVkX18UshV/vpKWoYtutcS2efoloN+okKMY+pYdvUnqi88znUhHPxSSX8t4'; +console.log(`Enc-Message(base64): ${encrypted_msg}`); +var decrypted_msg = decryptCardanoMessage(encrypted_msg, passphrase); +console.log(` Dec-Message(utf8): ${decrypted_msg}`) +console.log(`\n\n`); From c7acbd3202f7742412e4763eed633670ce4fb069 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:55:36 +0100 Subject: [PATCH 07/35] Create demo_via_PHP.php --- CIP-0020/codesamples/demo_via_PHP.php | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 CIP-0020/codesamples/demo_via_PHP.php diff --git a/CIP-0020/codesamples/demo_via_PHP.php b/CIP-0020/codesamples/demo_via_PHP.php new file mode 100644 index 0000000000..b116dc3f60 --- /dev/null +++ b/CIP-0020/codesamples/demo_via_PHP.php @@ -0,0 +1,88 @@ +// ------------------------------------------------------------------------------------------ +// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via PHP +// ------------------------------------------------------------------------------------------ + + 60) { + return ($elapsed / 60) . " minutes"; + } else { + return $elapsed . " seconds"; + } +} + +function getPbkdf2($password, $salt, $iterations) { + return openssl_pbkdf2($password, $salt, 48, $iterations, 'sha256'); +} + +function encryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { + if (debug) { + $start = microtime(true); + } + $salt = openssl_random_pseudo_bytes(8); + $encryptedText = "Salted__" . $salt; + + $keyIV = getPbkdf2($password, $salt, $iterations); + $key = substr($keyIV, 0, 32); + $iv = substr($keyIV, 32); + + $encryptedText .= openssl_encrypt($msg, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + $hashedEncryptedText = base64_encode($encryptedText); + + if (debug) { + echo "Done encrypting message in " . elapsedTime($start) . "\r\n"; + } + + return $hashedEncryptedText; +} + +function decryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { + if (debug) { + $start = microtime(true); + } + + $encryptedText = base64_decode($msg); + $salt = substr($encryptedText, 8, 8); + $cyphertext = substr($encryptedText, 16); + + $keyIV = getPbkdf2($password, $salt, $iterations); + $key = substr($keyIV, 0, 32); + $iv = substr($keyIV, 32); + + $decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + + if (debug) { + echo "Done decrypting message in " . elapsedTime($start) . "\r\n"; + } + + return $decrypted; +} + +$payload = "Testing message signing..."; + +// Basic signed/encrypted message w/ default password of "cardano" +$signed = encryptCardanoMessage($payload); + +// Basic signed/encrypted message w/ custom password +$passwordSigned = encryptCardanoMessage($payload, "You'll never guess it!"); + +// Basic signed/encrypted message w/ custom password and fewer iterations +$shortPasswordSigned = encryptCardanoMessage($payload, "Please", 20); + +// Basic decoding w/ default password of "cardano" +$unsigned = decryptCardanoMessage($signed); +echo "\$signed is: {$unsigned}\r\n"; + +// Basic decoding w/ custom password +$unsignedPassword = decryptCardanoMessage($passwordSigned, "You'll never guess it!"); +echo "\$passwordSigned is: {$unsignedPassword}\r\n"; + +// Basic decoding w/ custom password and fewer iterations +$shortUnsigned = decryptCardanoMessage($shortPasswordSigned, "Please", 20); +echo "\$shortPasswordSigned is: {$shortUnsigned}\r\n"; From 0050d558012c1705e0a7402898e3e801d87d74b2 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:55:58 +0100 Subject: [PATCH 08/35] Update demo_via_nodeJS.js --- CIP-0020/codesamples/demo_via_nodeJS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0020/codesamples/demo_via_nodeJS.js b/CIP-0020/codesamples/demo_via_nodeJS.js index 5efde7bbcf..43e7139841 100644 --- a/CIP-0020/codesamples/demo_via_nodeJS.js +++ b/CIP-0020/codesamples/demo_via_nodeJS.js @@ -1,5 +1,5 @@ // ---------------------------------------------------------------------------------------------- -// Demonstation implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE.JS +// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE.JS // ---------------------------------------------------------------------------------------------- const crypto = require('crypto'); From 7b9290f16f72b06b321ae8ad07aa4251b639073b Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:58:48 +0100 Subject: [PATCH 09/35] Update README.md --- CIP-0020/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 89861c8d7d..4370e0b90d 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -131,8 +131,8 @@ The encryption is based on a given passphrase, which can be choosen by the user. The part that is encrypted/decrypted is the value of the **msg** key from a normal transaction metadata json, the array with the message(s) string(s). -Example implementations for node.js, PHP, etc. can be found in the [codesamples](codesamples/) folder. - +:warning: Example implementations for node.js, PHP, etc. can be found in the [codesamples](codesamples/) folder. **Message decryption should be done on the user frontend if possible.** + ### Encryption/Decryption example on the console - basic mode First, generate a normal metadata transaction message. There is no difference yet. From 0553507c9b6369035137d82e282ca03bdf8a04a5 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:03:45 +0100 Subject: [PATCH 10/35] Update README.md --- CIP-0020/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 4370e0b90d..715fd2f798 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -211,6 +211,8 @@ Which results in the original content of the **msg** key: **CNTools**:
![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) From 199a8f5c19e1844211f627a5fa1f73fc166bcc92 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:04:49 +0100 Subject: [PATCH 11/35] Update README.md --- CIP-0020/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 715fd2f798..2c3efc4a3b 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -30,6 +30,7 @@ Current Tools/Sites/Explorers that have implemented it already or have plans to * [CardanoCommunityWallet](https://ccwallet.io) * [CardanoWall](https://cardanowall.com) * [CNFT](https://cnft.io) +* [Cardano Explorer](https://cexplorer.io) # Specification From 6f877ce838a87f179ca077d0f155ded78f4c8097 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:09:36 +0100 Subject: [PATCH 12/35] Create cip0020-democode-PHP.php --- CIP-0020/codesamples/cip0020-democode-PHP.php | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 CIP-0020/codesamples/cip0020-democode-PHP.php diff --git a/CIP-0020/codesamples/cip0020-democode-PHP.php b/CIP-0020/codesamples/cip0020-democode-PHP.php new file mode 100644 index 0000000000..b116dc3f60 --- /dev/null +++ b/CIP-0020/codesamples/cip0020-democode-PHP.php @@ -0,0 +1,88 @@ +// ------------------------------------------------------------------------------------------ +// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via PHP +// ------------------------------------------------------------------------------------------ + + 60) { + return ($elapsed / 60) . " minutes"; + } else { + return $elapsed . " seconds"; + } +} + +function getPbkdf2($password, $salt, $iterations) { + return openssl_pbkdf2($password, $salt, 48, $iterations, 'sha256'); +} + +function encryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { + if (debug) { + $start = microtime(true); + } + $salt = openssl_random_pseudo_bytes(8); + $encryptedText = "Salted__" . $salt; + + $keyIV = getPbkdf2($password, $salt, $iterations); + $key = substr($keyIV, 0, 32); + $iv = substr($keyIV, 32); + + $encryptedText .= openssl_encrypt($msg, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + $hashedEncryptedText = base64_encode($encryptedText); + + if (debug) { + echo "Done encrypting message in " . elapsedTime($start) . "\r\n"; + } + + return $hashedEncryptedText; +} + +function decryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { + if (debug) { + $start = microtime(true); + } + + $encryptedText = base64_decode($msg); + $salt = substr($encryptedText, 8, 8); + $cyphertext = substr($encryptedText, 16); + + $keyIV = getPbkdf2($password, $salt, $iterations); + $key = substr($keyIV, 0, 32); + $iv = substr($keyIV, 32); + + $decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + + if (debug) { + echo "Done decrypting message in " . elapsedTime($start) . "\r\n"; + } + + return $decrypted; +} + +$payload = "Testing message signing..."; + +// Basic signed/encrypted message w/ default password of "cardano" +$signed = encryptCardanoMessage($payload); + +// Basic signed/encrypted message w/ custom password +$passwordSigned = encryptCardanoMessage($payload, "You'll never guess it!"); + +// Basic signed/encrypted message w/ custom password and fewer iterations +$shortPasswordSigned = encryptCardanoMessage($payload, "Please", 20); + +// Basic decoding w/ default password of "cardano" +$unsigned = decryptCardanoMessage($signed); +echo "\$signed is: {$unsigned}\r\n"; + +// Basic decoding w/ custom password +$unsignedPassword = decryptCardanoMessage($passwordSigned, "You'll never guess it!"); +echo "\$passwordSigned is: {$unsignedPassword}\r\n"; + +// Basic decoding w/ custom password and fewer iterations +$shortUnsigned = decryptCardanoMessage($shortPasswordSigned, "Please", 20); +echo "\$shortPasswordSigned is: {$shortUnsigned}\r\n"; From 30f59f94de8857594d04a24df6ebfd16ee8f53be Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:10:08 +0100 Subject: [PATCH 13/35] Delete demo_via_PHP.php --- CIP-0020/codesamples/demo_via_PHP.php | 88 --------------------------- 1 file changed, 88 deletions(-) delete mode 100644 CIP-0020/codesamples/demo_via_PHP.php diff --git a/CIP-0020/codesamples/demo_via_PHP.php b/CIP-0020/codesamples/demo_via_PHP.php deleted file mode 100644 index b116dc3f60..0000000000 --- a/CIP-0020/codesamples/demo_via_PHP.php +++ /dev/null @@ -1,88 +0,0 @@ -// ------------------------------------------------------------------------------------------ -// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via PHP -// ------------------------------------------------------------------------------------------ - - 60) { - return ($elapsed / 60) . " minutes"; - } else { - return $elapsed . " seconds"; - } -} - -function getPbkdf2($password, $salt, $iterations) { - return openssl_pbkdf2($password, $salt, 48, $iterations, 'sha256'); -} - -function encryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { - if (debug) { - $start = microtime(true); - } - $salt = openssl_random_pseudo_bytes(8); - $encryptedText = "Salted__" . $salt; - - $keyIV = getPbkdf2($password, $salt, $iterations); - $key = substr($keyIV, 0, 32); - $iv = substr($keyIV, 32); - - $encryptedText .= openssl_encrypt($msg, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); - $hashedEncryptedText = base64_encode($encryptedText); - - if (debug) { - echo "Done encrypting message in " . elapsedTime($start) . "\r\n"; - } - - return $hashedEncryptedText; -} - -function decryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { - if (debug) { - $start = microtime(true); - } - - $encryptedText = base64_decode($msg); - $salt = substr($encryptedText, 8, 8); - $cyphertext = substr($encryptedText, 16); - - $keyIV = getPbkdf2($password, $salt, $iterations); - $key = substr($keyIV, 0, 32); - $iv = substr($keyIV, 32); - - $decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); - - if (debug) { - echo "Done decrypting message in " . elapsedTime($start) . "\r\n"; - } - - return $decrypted; -} - -$payload = "Testing message signing..."; - -// Basic signed/encrypted message w/ default password of "cardano" -$signed = encryptCardanoMessage($payload); - -// Basic signed/encrypted message w/ custom password -$passwordSigned = encryptCardanoMessage($payload, "You'll never guess it!"); - -// Basic signed/encrypted message w/ custom password and fewer iterations -$shortPasswordSigned = encryptCardanoMessage($payload, "Please", 20); - -// Basic decoding w/ default password of "cardano" -$unsigned = decryptCardanoMessage($signed); -echo "\$signed is: {$unsigned}\r\n"; - -// Basic decoding w/ custom password -$unsignedPassword = decryptCardanoMessage($passwordSigned, "You'll never guess it!"); -echo "\$passwordSigned is: {$unsignedPassword}\r\n"; - -// Basic decoding w/ custom password and fewer iterations -$shortUnsigned = decryptCardanoMessage($shortPasswordSigned, "Please", 20); -echo "\$shortPasswordSigned is: {$shortUnsigned}\r\n"; From 9e3b74675ce902786d09fb3174f03f195fe18491 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:11:18 +0100 Subject: [PATCH 14/35] Create cip0020-democode-NODEJS.js --- .../codesamples/cip0020-democode-NODEJS.js | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 CIP-0020/codesamples/cip0020-democode-NODEJS.js diff --git a/CIP-0020/codesamples/cip0020-democode-NODEJS.js b/CIP-0020/codesamples/cip0020-democode-NODEJS.js new file mode 100644 index 0000000000..2d42418b27 --- /dev/null +++ b/CIP-0020/codesamples/cip0020-democode-NODEJS.js @@ -0,0 +1,97 @@ +// ----------------------------------------------------------------------------------------------- +// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE-JS +// ----------------------------------------------------------------------------------------------- + +const crypto = require('crypto'); + +// +// Calculate the KeyIV via the PasswordBasedKeyDerivedFormat2 pbkdf2 method, 10000 iterations, 48 bytes long, sha256 +// +function calc_KeyIV(passphrase, salt) { //passphrase as utf8 string, salt as hexstring + const key_IV = crypto.pbkdf2Sync(Buffer.from(passphrase,'utf8'), Buffer.from(salt,'hex'), 10000, 48, 'sha256').toString('hex') + console.log(` keyIV: ${key_IV}`); + return key_IV; //hex-string +} + +// +// Encryption Function +// +function encryptCardanoMessage(decrypted_msg, passphrase = 'cardano') { //decrypted_msg as utf8 string, passphrase as utf8 string(defaults to cardano) + //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext + //Build up the encrypted Message as hex string + var encrypted_hex = Buffer.from('Salted__','utf8').toString('hex'); + //Generate the random salt + var salt = crypto.randomBytes(8).toString('hex'); + encrypted_hex += salt; //append the salt + console.log(` salt: ${salt}`); + //Calculate the Key+IV + var keyIV = calc_KeyIV(passphrase, salt) + //The key itself is the first 32 Bytes (char 0-64 in hex string) + var key = keyIV.substring(0,64); + //The IV (initialization vector) is 16 Bytes and follows the key + var iv = keyIV.substring(64); + console.log(` key: ${key}`); + console.log(` iv: ${iv}`); + //Encrypt the message + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); + try { + var cyphertext = cipher.update(decrypted_msg, 'utf8', 'hex') + cipher.final('hex'); + } catch (error) { console.error(`Could not encrypt the message\n${error}`); process.exit(1); } + console.log(` cyphertext: ${cyphertext}`); + encrypted_hex += cyphertext; //append the cyphertext + console.log(` Enc-Message(hex): ${encrypted_hex}`); + return Buffer.from(encrypted_hex,'hex').toString('base64'); //base64 string +} + + +// +// Decryption Function +// +function decryptCardanoMessage(encrypted_msg, passphrase = 'cardano') { //encrypted_msg as base64 string, passphrase as utf8 string(defaults to cardano) + //Encrypted Message is base64 encoded, convert it to hex + const encrypted_hex = Buffer.from(encrypted_msg, 'base64').toString('hex'); + console.log(` Enc-Message(hex): ${encrypted_hex}`); + //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext + //Salt is byte 9-16 in the Encrypted Message (char 16-32 in a hex string) + var salt = encrypted_hex.substring(16,32); + console.log(` salt: ${salt}`); + //Cyphertext is all the rest after the salt (starting with char 32 in a hex string) + var cyphertext = encrypted_hex.substring(32); + console.log(` cyphertext: ${cyphertext}`); + //Calculate the Key+IV + var keyIV = calc_KeyIV(passphrase, salt) + //The key itself is the first 32 Bytes (char 0-64 in hex string) + var key = keyIV.substring(0,64); + //The IV (initialization vector) is 16 Bytes and follows the key + var iv = keyIV.substring(64); + console.log(` key: ${key}`); + console.log(` iv: ${iv}`); + //Decrypt the cyphertext with the key and the iv + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); + try { + var decr_msg = decipher.update(cyphertext, 'hex').toString('utf8') + decipher.final('utf8'); + } catch (error) { console.error(`Could not decrypt the message\n${error}`); process.exit(1); } + return decr_msg; //utf8 +} + +//------------------------- +// DEMO Encrypt and Decrypt +//------------------------- + +const passphrase = 'cardano'; //Using default passphrase 'cardano' + +// Encryption +console.log(`--- Encryption ---`); +var decrypted_msg = 'Hi, this is a test-message. Best regards, Martin'; +console.log(` Dec-Message(utf8): ${decrypted_msg}`) +var encrypted_msg = encryptCardanoMessage(decrypted_msg, passphrase); +console.log(`Enc-Message(base64): ${encrypted_msg}`); +console.log(`\n\n`); + +// Decryption +console.log(`--- Decryption ---`); +var encrypted_msg = 'U2FsdGVkX18UshV/vpKWoYtutcS2efoloN+okKMY+pYdvUnqi88znUhHPxSSX8t4'; +console.log(`Enc-Message(base64): ${encrypted_msg}`); +var decrypted_msg = decryptCardanoMessage(encrypted_msg, passphrase); +console.log(` Dec-Message(utf8): ${decrypted_msg}`) +console.log(`\n\n`); From 629e355afd5f54de0ff54165772afedef6133a2d Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:11:43 +0100 Subject: [PATCH 15/35] Delete demo_via_nodeJS.js --- CIP-0020/codesamples/demo_via_nodeJS.js | 97 ------------------------- 1 file changed, 97 deletions(-) delete mode 100644 CIP-0020/codesamples/demo_via_nodeJS.js diff --git a/CIP-0020/codesamples/demo_via_nodeJS.js b/CIP-0020/codesamples/demo_via_nodeJS.js deleted file mode 100644 index 43e7139841..0000000000 --- a/CIP-0020/codesamples/demo_via_nodeJS.js +++ /dev/null @@ -1,97 +0,0 @@ -// ---------------------------------------------------------------------------------------------- -// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE.JS -// ---------------------------------------------------------------------------------------------- - -const crypto = require('crypto'); - -// -// Calculate the KeyIV via the PasswordBasedKeyDerivedFormat2 pbkdf2 method, 10000 iterations, 48 bytes long, sha256 -// -function calc_KeyIV(passphrase, salt) { //passphrase as utf8 string, salt as hexstring - const key_IV = crypto.pbkdf2Sync(Buffer.from(passphrase,'utf8'), Buffer.from(salt,'hex'), 10000, 48, 'sha256').toString('hex') - console.log(` keyIV: ${key_IV}`); - return key_IV; //hex-string -} - -// -// Encryption Function -// -function encryptCardanoMessage(decrypted_msg, passphrase = 'cardano') { //decrypted_msg as utf8 string, passphrase as utf8 string(defaults to cardano) - //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext - //Build up the encrypted Message as hex string - var encrypted_hex = Buffer.from('Salted__','utf8').toString('hex'); - //Generate the random salt - var salt = crypto.randomBytes(8).toString('hex'); - encrypted_hex += salt; //append the salt - console.log(` salt: ${salt}`); - //Calculate the Key+IV - var keyIV = calc_KeyIV(passphrase, salt) - //The key itself is the first 32 Bytes (char 0-64 in hex string) - var key = keyIV.substring(0,64); - //The IV (initialization vector) is 16 Bytes and follows the key - var iv = keyIV.substring(64); - console.log(` key: ${key}`); - console.log(` iv: ${iv}`); - //Encrypt the message - const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); - try { - var cyphertext = cipher.update(decrypted_msg, 'utf8', 'hex') + cipher.final('hex'); - } catch (error) { console.error(`Could not encrypt the message\n${error}`); process.exit(1); } - console.log(` cyphertext: ${cyphertext}`); - encrypted_hex += cyphertext; //append the cyphertext - console.log(` Enc-Message(hex): ${encrypted_hex}`); - return Buffer.from(encrypted_hex,'hex').toString('base64'); //base64 string -} - - -// -// Decryption Function -// -function decryptCardanoMessage(encrypted_msg, passphrase = 'cardano') { //encrypted_msg as base64 string, passphrase as utf8 string(defaults to cardano) - //Encrypted Message is base64 encoded, convert it to hex - const encrypted_hex = Buffer.from(encrypted_msg, 'base64').toString('hex'); - console.log(` Enc-Message(hex): ${encrypted_hex}`); - //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext - //Salt is byte 9-16 in the Encrypted Message (char 16-32 in a hex string) - var salt = encrypted_hex.substring(16,32); - console.log(` salt: ${salt}`); - //Cyphertext is all the rest after the salt (starting with char 32 in a hex string) - var cyphertext = encrypted_hex.substring(32); - console.log(` cyphertext: ${cyphertext}`); - //Calculate the Key+IV - var keyIV = calc_KeyIV(passphrase, salt) - //The key itself is the first 32 Bytes (char 0-64 in hex string) - var key = keyIV.substring(0,64); - //The IV (initialization vector) is 16 Bytes and follows the key - var iv = keyIV.substring(64); - console.log(` key: ${key}`); - console.log(` iv: ${iv}`); - //Decrypt the cyphertext with the key and the iv - const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); - try { - var decr_msg = decipher.update(cyphertext, 'hex').toString('utf8') + decipher.final('utf8'); - } catch (error) { console.error(`Could not decrypt the message\n${error}`); process.exit(1); } - return decr_msg; //utf8 -} - -//------------------------- -// DEMO Encrypt and Decrypt -//------------------------- - -const passphrase = 'cardano'; //Using default passphrase 'cardano' - -// Encryption -console.log(`--- Encryption ---`); -var decrypted_msg = 'Hi, this is a test-message. Best regards, Martin'; -console.log(` Dec-Message(utf8): ${decrypted_msg}`) -var encrypted_msg = encryptCardanoMessage(decrypted_msg, passphrase); -console.log(`Enc-Message(base64): ${encrypted_msg}`); -console.log(`\n\n`); - -// Decryption -console.log(`--- Decryption ---`); -var encrypted_msg = 'U2FsdGVkX18UshV/vpKWoYtutcS2efoloN+okKMY+pYdvUnqi88znUhHPxSSX8t4'; -console.log(`Enc-Message(base64): ${encrypted_msg}`); -var decrypted_msg = decryptCardanoMessage(encrypted_msg, passphrase); -console.log(` Dec-Message(utf8): ${decrypted_msg}`) -console.log(`\n\n`); From b6bf2b3fc95cf54bf1f9984c5164ce582e1760a7 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:14:12 +0100 Subject: [PATCH 16/35] Create normal-message-metadata.json --- CIP-0020/codesamples/normal-message-metadata.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CIP-0020/codesamples/normal-message-metadata.json diff --git a/CIP-0020/codesamples/normal-message-metadata.json b/CIP-0020/codesamples/normal-message-metadata.json new file mode 100644 index 0000000000..9ff9494fb1 --- /dev/null +++ b/CIP-0020/codesamples/normal-message-metadata.json @@ -0,0 +1,5 @@ +{ + "674": { + "msg": ["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"] + } +} From 02cbc5c8eae2ac20dc7b8754079d0b6e31a4f323 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:14:35 +0100 Subject: [PATCH 17/35] Create encrypted-message-metadata.json --- CIP-0020/codesamples/encrypted-message-metadata.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CIP-0020/codesamples/encrypted-message-metadata.json diff --git a/CIP-0020/codesamples/encrypted-message-metadata.json b/CIP-0020/codesamples/encrypted-message-metadata.json new file mode 100644 index 0000000000..37d693a297 --- /dev/null +++ b/CIP-0020/codesamples/encrypted-message-metadata.json @@ -0,0 +1,11 @@ +{ + "674": + { + "enc": "basic", + "msg": + [ + "U2FsdGVkX1/5Y0A7l8xK686rvLsmPviTlna2n3P/ADNm89Ynr1UPZ/Q6bynbe28Y", + "/zWYOB9PAGt+bq1L0z/W2LNHe92HTN/Fwz16aHa98TOsgM3q8tAR4NSqrLZVu1H7" + ] + } +} From 400fdb54e369e8574cf09ac966d37a4928d32ca8 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:36:54 +0100 Subject: [PATCH 18/35] Create cip0020-democode-BASH.sh --- CIP-0020/codesamples/cip0020-democode-BASH.sh | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 CIP-0020/codesamples/cip0020-democode-BASH.sh diff --git a/CIP-0020/codesamples/cip0020-democode-BASH.sh b/CIP-0020/codesamples/cip0020-democode-BASH.sh new file mode 100644 index 0000000000..92225ef6a8 --- /dev/null +++ b/CIP-0020/codesamples/cip0020-democode-BASH.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# -------------------------------------------------------------------------------------------- +# Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via BASH +# -------------------------------------------------------------------------------------------- + + +#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 "cardano") +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 "cardano") +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 From cb63808798ab496aa8e2fc26f95e81d4f3a64052 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 16:38:31 +0100 Subject: [PATCH 19/35] Update cip0020-democode-BASH.sh --- CIP-0020/codesamples/cip0020-democode-BASH.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CIP-0020/codesamples/cip0020-democode-BASH.sh b/CIP-0020/codesamples/cip0020-democode-BASH.sh index 92225ef6a8..0fa135e493 100644 --- a/CIP-0020/codesamples/cip0020-democode-BASH.sh +++ b/CIP-0020/codesamples/cip0020-democode-BASH.sh @@ -4,6 +4,9 @@ # 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:" @@ -12,7 +15,7 @@ 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 "cardano") +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 @@ -35,7 +38,7 @@ 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 "cardano") +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 From 5c593ba5c7a33854b14a43f2d199fd40f08ac23b Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:03:41 +0100 Subject: [PATCH 20/35] Update README.md --- CIP-0020/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 2c3efc4a3b..1431b8932c 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -98,7 +98,7 @@ The specification update for encrypted messages takes advantage of the simple or "enc": "", "msg": [ - "encrypted-string 1" //Optional: ,"encrypted-string 2","encyrpted-string 3" ... + "base64-string 1", "base64-string 2", "base64-string 3" ... ] } } From fe27b147a2b1c9cf0371c8749977b16427402ef0 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:07:28 +0100 Subject: [PATCH 21/35] Update README.md --- CIP-0020/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 1431b8932c..f56fdde143 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -132,7 +132,9 @@ The encryption is based on a given passphrase, which can be choosen by the user. The part that is encrypted/decrypted is the value of the **msg** key from a normal transaction metadata json, the array with the message(s) string(s). -:warning: Example implementations for node.js, PHP, etc. can be found in the [codesamples](codesamples/) folder. **Message decryption should be done on the user frontend if possible.** +Example implementations for node.js, PHP, bash, etc. can be found in the [codesamples](codesamples/) folder. + +:warning: **Message decryption should be done on the user frontend if possible, not via server callbacks.** ### Encryption/Decryption example on the console - basic mode From 7dd544c793a46c12f120be6e942414f9b266a286 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:10:32 +0100 Subject: [PATCH 22/35] Update README.md --- CIP-0020/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index f56fdde143..a81441fb93 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -149,7 +149,7 @@ First, generate a normal metadata transaction message. There is no difference ye } ``` -Encrypt the message via openssl and the default passprase **cardano**: +Encrypt the message (value of the `msg:` key) via openssl and the default passprase **cardano**: ``` console openssl enc -e -aes-256-cbc -pbkdf2 -iter 10000 -a -k "cardano" <<< '["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]' ``` From 5e956770d618a0fe655c8247d5200904518ddf24 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:17:04 +0100 Subject: [PATCH 23/35] Update README.md --- CIP-0020/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index a81441fb93..d56e92514f 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -86,9 +86,9 @@ The number of theses **message-strings** must be at least one for a single messa 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 passphrasw - it is much more complicated for the man-in-the-middle listener to collect data on the fly. +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 istead of an maybe autodecrypted one. More on the autodecryption later. +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: ``` From b29186cb4733fa71491f5b672fe5d3df4cd4cf06 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 21:08:12 +0100 Subject: [PATCH 24/35] Update README.md --- CIP-0020/README.md | 53 +++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index d56e92514f..60b7084ba0 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -1,7 +1,7 @@ --- CIP: 20 Title: Transaction message/comment metadata -Authors: Martin Lang , Ola Ahlman , Andrew Westberg +Authors: Martin Lang , Ola Ahlman , Andrew Westberg , Adam Dean Comments-URI: no comments yet Status: Active Type: Informational @@ -21,16 +21,21 @@ 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: +Current Tools/Sites/Explorers that have implemented it already: * [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) * [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/) # Specification @@ -107,6 +112,8 @@ The format is identical to the normal one, with a simple addition of the `enc` ( 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. +  

+ ### Encryption modes: * **plain** - no encryption at all @@ -135,10 +142,12 @@ The part that is encrypted/decrypted is the value of the **msg** key from a norm Example implementations for node.js, PHP, bash, etc. can be found in the [codesamples](codesamples/) folder. :warning: **Message decryption should be done on the user frontend if possible, not via server callbacks.** - + +  

+ ### Encryption/Decryption example on the console - basic mode -First, generate a normal metadata transaction message. There is no difference yet. +First, generate a normal metadata transaction message. **normal-message-metadata.json**: ``` json @@ -149,18 +158,26 @@ First, generate a normal metadata transaction message. There is no difference ye } ``` -Encrypt the message (value of the `msg:` key) via openssl and the default passprase **cardano**: +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"]' ``` -Result are the base64 encoded strings: +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. +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 @@ -190,23 +207,23 @@ jq -crM ".\"674\".msg[]" encrypted-message-metadata.json | openssl enc -d -aes-2 ``` Which results in the original content of the **msg** key: + `["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"]`  

-# Some Integration examples +## Some Integration examples (standard/unencrypted) **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. ![image](https://user-images.githubusercontent.com/47434720/129110626-6bc5b3c3-102d-4793-b508-7d4190b31cf7.png) @@ -214,7 +231,7 @@ Which results in the original content of the **msg** key: **CNTools**:
![image](https://user-images.githubusercontent.com/47434720/130353491-fc0f3a69-1937-4e72-b680-c04cc069b5c4.png) -# Integration examples for encrypted messages +## 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) @@ -223,11 +240,13 @@ Which results in the original content of the **msg** key: # 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 ## From 8ad5e42d114984f774a06cfd8de59e04c38a6ff5 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 21:18:54 +0100 Subject: [PATCH 25/35] Update README.md --- CIP-0020/README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 60b7084ba0..7c18593ea9 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -117,12 +117,15 @@ The value given in the `enc` field references an entry in the [Encryption Mode J ### 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 based salted symmetric encryption via passpharse (+default passphrase) +* **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: +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)", @@ -133,13 +136,21 @@ Lets list the entry from the [Encryption Mode Json](cip0020-encryption-modes.jso "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. +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. +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. -The part that is encrypted/decrypted is the value of the **msg** key from a normal transaction metadata json, the array with the message(s) string(s). +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) -Example implementations for node.js, PHP, bash, etc. can be found in the [codesamples](codesamples/) folder. +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.** From 24d892f33936984ae5815506d0da7e3a1fceee3e Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Tue, 29 Nov 2022 22:22:57 +0100 Subject: [PATCH 26/35] Update README.md --- CIP-0020/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index 7c18593ea9..c75855181f 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -21,7 +21,7 @@ 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: +Some of the current Tools/Sites/Explorers that have implemented it already: * [CNTools](https://cardano-community.github.io/guild-operators/#/Scripts/cntools) * [JorManager](https://bitbucket.org/muamw10/jormanager/) * [StakePoolOperator Scripts](https://github.com/gitmachtl/scripts) @@ -29,6 +29,7 @@ Current Tools/Sites/Explorers that have implemented it already: * [AdaStat.net](https://adastat.net) * [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/) @@ -36,6 +37,7 @@ Current Tools/Sites/Explorers that have implemented it already: * [MuesliSwap](https://muesliswap.com/) * [DripDropz.io](https://dripdropz.io/) * [Typhon Wallet](https://typhonwallet.io/) +* [Ledger Live](https://www.ledger.com/) # Specification @@ -225,6 +227,9 @@ Which results in the original content of the **msg** key: ## 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) From b9672fe232030e15ffd9a7af560e15b285107272 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Sat, 3 Dec 2022 14:17:49 +0100 Subject: [PATCH 27/35] Added 'SPO Scripts' as an encrypted msg integration example --- CIP-0020/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index c75855181f..d80d65e2db 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -241,7 +241,7 @@ Which results in the original content of the **msg** key: ![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**:
@@ -252,6 +252,8 @@ Which results in the original content of the **msg** key: **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:"` 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 From 6441cd351ccc7a25d878e1ffc5e5d26f68161e25 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:58:14 +0100 Subject: [PATCH 28/35] Delete cip0020-encryption-modes.json --- CIP-0020/cip0020-encryption-modes.json | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 CIP-0020/cip0020-encryption-modes.json diff --git a/CIP-0020/cip0020-encryption-modes.json b/CIP-0020/cip0020-encryption-modes.json deleted file mode 100644 index 2474cfc231..0000000000 --- a/CIP-0020/cip0020-encryption-modes.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "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" - } -} From 85f8fa7ec6147b43b6a0fdf153a2b08be211ebef Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:58:29 +0100 Subject: [PATCH 29/35] Delete cip0020-democode-BASH.sh --- CIP-0020/codesamples/cip0020-democode-BASH.sh | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 CIP-0020/codesamples/cip0020-democode-BASH.sh diff --git a/CIP-0020/codesamples/cip0020-democode-BASH.sh b/CIP-0020/codesamples/cip0020-democode-BASH.sh deleted file mode 100644 index 0fa135e493..0000000000 --- a/CIP-0020/codesamples/cip0020-democode-BASH.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/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 From dd923ce5cafacc1d3cef3afcec144988fc209adb Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:58:37 +0100 Subject: [PATCH 30/35] Delete cip0020-democode-NODEJS.js --- .../codesamples/cip0020-democode-NODEJS.js | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 CIP-0020/codesamples/cip0020-democode-NODEJS.js diff --git a/CIP-0020/codesamples/cip0020-democode-NODEJS.js b/CIP-0020/codesamples/cip0020-democode-NODEJS.js deleted file mode 100644 index 2d42418b27..0000000000 --- a/CIP-0020/codesamples/cip0020-democode-NODEJS.js +++ /dev/null @@ -1,97 +0,0 @@ -// ----------------------------------------------------------------------------------------------- -// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via NODE-JS -// ----------------------------------------------------------------------------------------------- - -const crypto = require('crypto'); - -// -// Calculate the KeyIV via the PasswordBasedKeyDerivedFormat2 pbkdf2 method, 10000 iterations, 48 bytes long, sha256 -// -function calc_KeyIV(passphrase, salt) { //passphrase as utf8 string, salt as hexstring - const key_IV = crypto.pbkdf2Sync(Buffer.from(passphrase,'utf8'), Buffer.from(salt,'hex'), 10000, 48, 'sha256').toString('hex') - console.log(` keyIV: ${key_IV}`); - return key_IV; //hex-string -} - -// -// Encryption Function -// -function encryptCardanoMessage(decrypted_msg, passphrase = 'cardano') { //decrypted_msg as utf8 string, passphrase as utf8 string(defaults to cardano) - //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext - //Build up the encrypted Message as hex string - var encrypted_hex = Buffer.from('Salted__','utf8').toString('hex'); - //Generate the random salt - var salt = crypto.randomBytes(8).toString('hex'); - encrypted_hex += salt; //append the salt - console.log(` salt: ${salt}`); - //Calculate the Key+IV - var keyIV = calc_KeyIV(passphrase, salt) - //The key itself is the first 32 Bytes (char 0-64 in hex string) - var key = keyIV.substring(0,64); - //The IV (initialization vector) is 16 Bytes and follows the key - var iv = keyIV.substring(64); - console.log(` key: ${key}`); - console.log(` iv: ${iv}`); - //Encrypt the message - const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); - try { - var cyphertext = cipher.update(decrypted_msg, 'utf8', 'hex') + cipher.final('hex'); - } catch (error) { console.error(`Could not encrypt the message\n${error}`); process.exit(1); } - console.log(` cyphertext: ${cyphertext}`); - encrypted_hex += cyphertext; //append the cyphertext - console.log(` Enc-Message(hex): ${encrypted_hex}`); - return Buffer.from(encrypted_hex,'hex').toString('base64'); //base64 string -} - - -// -// Decryption Function -// -function decryptCardanoMessage(encrypted_msg, passphrase = 'cardano') { //encrypted_msg as base64 string, passphrase as utf8 string(defaults to cardano) - //Encrypted Message is base64 encoded, convert it to hex - const encrypted_hex = Buffer.from(encrypted_msg, 'base64').toString('hex'); - console.log(` Enc-Message(hex): ${encrypted_hex}`); - //Encrypted Message (salted) looks like 'Salted__' + 8 bytes salt + cyphertext - //Salt is byte 9-16 in the Encrypted Message (char 16-32 in a hex string) - var salt = encrypted_hex.substring(16,32); - console.log(` salt: ${salt}`); - //Cyphertext is all the rest after the salt (starting with char 32 in a hex string) - var cyphertext = encrypted_hex.substring(32); - console.log(` cyphertext: ${cyphertext}`); - //Calculate the Key+IV - var keyIV = calc_KeyIV(passphrase, salt) - //The key itself is the first 32 Bytes (char 0-64 in hex string) - var key = keyIV.substring(0,64); - //The IV (initialization vector) is 16 Bytes and follows the key - var iv = keyIV.substring(64); - console.log(` key: ${key}`); - console.log(` iv: ${iv}`); - //Decrypt the cyphertext with the key and the iv - const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key,'hex'), Buffer.from(iv,'hex')); - try { - var decr_msg = decipher.update(cyphertext, 'hex').toString('utf8') + decipher.final('utf8'); - } catch (error) { console.error(`Could not decrypt the message\n${error}`); process.exit(1); } - return decr_msg; //utf8 -} - -//------------------------- -// DEMO Encrypt and Decrypt -//------------------------- - -const passphrase = 'cardano'; //Using default passphrase 'cardano' - -// Encryption -console.log(`--- Encryption ---`); -var decrypted_msg = 'Hi, this is a test-message. Best regards, Martin'; -console.log(` Dec-Message(utf8): ${decrypted_msg}`) -var encrypted_msg = encryptCardanoMessage(decrypted_msg, passphrase); -console.log(`Enc-Message(base64): ${encrypted_msg}`); -console.log(`\n\n`); - -// Decryption -console.log(`--- Decryption ---`); -var encrypted_msg = 'U2FsdGVkX18UshV/vpKWoYtutcS2efoloN+okKMY+pYdvUnqi88znUhHPxSSX8t4'; -console.log(`Enc-Message(base64): ${encrypted_msg}`); -var decrypted_msg = decryptCardanoMessage(encrypted_msg, passphrase); -console.log(` Dec-Message(utf8): ${decrypted_msg}`) -console.log(`\n\n`); From ccfcb0297ef9d0435fa9c3ce6ad003ad1d053848 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:58:59 +0100 Subject: [PATCH 31/35] Delete cip0020-democode-PHP.php --- CIP-0020/codesamples/cip0020-democode-PHP.php | 88 ------------------- 1 file changed, 88 deletions(-) delete mode 100644 CIP-0020/codesamples/cip0020-democode-PHP.php diff --git a/CIP-0020/codesamples/cip0020-democode-PHP.php b/CIP-0020/codesamples/cip0020-democode-PHP.php deleted file mode 100644 index b116dc3f60..0000000000 --- a/CIP-0020/codesamples/cip0020-democode-PHP.php +++ /dev/null @@ -1,88 +0,0 @@ -// ------------------------------------------------------------------------------------------ -// Demonstration implementation of CIP-0020 Transaction Messages Encryption/Decryption via PHP -// ------------------------------------------------------------------------------------------ - - 60) { - return ($elapsed / 60) . " minutes"; - } else { - return $elapsed . " seconds"; - } -} - -function getPbkdf2($password, $salt, $iterations) { - return openssl_pbkdf2($password, $salt, 48, $iterations, 'sha256'); -} - -function encryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { - if (debug) { - $start = microtime(true); - } - $salt = openssl_random_pseudo_bytes(8); - $encryptedText = "Salted__" . $salt; - - $keyIV = getPbkdf2($password, $salt, $iterations); - $key = substr($keyIV, 0, 32); - $iv = substr($keyIV, 32); - - $encryptedText .= openssl_encrypt($msg, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); - $hashedEncryptedText = base64_encode($encryptedText); - - if (debug) { - echo "Done encrypting message in " . elapsedTime($start) . "\r\n"; - } - - return $hashedEncryptedText; -} - -function decryptCardanoMessage($msg, $password = 'cardano', $iterations = 10000) { - if (debug) { - $start = microtime(true); - } - - $encryptedText = base64_decode($msg); - $salt = substr($encryptedText, 8, 8); - $cyphertext = substr($encryptedText, 16); - - $keyIV = getPbkdf2($password, $salt, $iterations); - $key = substr($keyIV, 0, 32); - $iv = substr($keyIV, 32); - - $decrypted = openssl_decrypt($cyphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); - - if (debug) { - echo "Done decrypting message in " . elapsedTime($start) . "\r\n"; - } - - return $decrypted; -} - -$payload = "Testing message signing..."; - -// Basic signed/encrypted message w/ default password of "cardano" -$signed = encryptCardanoMessage($payload); - -// Basic signed/encrypted message w/ custom password -$passwordSigned = encryptCardanoMessage($payload, "You'll never guess it!"); - -// Basic signed/encrypted message w/ custom password and fewer iterations -$shortPasswordSigned = encryptCardanoMessage($payload, "Please", 20); - -// Basic decoding w/ default password of "cardano" -$unsigned = decryptCardanoMessage($signed); -echo "\$signed is: {$unsigned}\r\n"; - -// Basic decoding w/ custom password -$unsignedPassword = decryptCardanoMessage($passwordSigned, "You'll never guess it!"); -echo "\$passwordSigned is: {$unsignedPassword}\r\n"; - -// Basic decoding w/ custom password and fewer iterations -$shortUnsigned = decryptCardanoMessage($shortPasswordSigned, "Please", 20); -echo "\$shortPasswordSigned is: {$shortUnsigned}\r\n"; From cc10ca9f70fcfc1f40934a8c24d65e7ea8e2bbc1 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:59:05 +0100 Subject: [PATCH 32/35] Delete encrypted-message-metadata.json --- CIP-0020/codesamples/encrypted-message-metadata.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 CIP-0020/codesamples/encrypted-message-metadata.json diff --git a/CIP-0020/codesamples/encrypted-message-metadata.json b/CIP-0020/codesamples/encrypted-message-metadata.json deleted file mode 100644 index 37d693a297..0000000000 --- a/CIP-0020/codesamples/encrypted-message-metadata.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "674": - { - "enc": "basic", - "msg": - [ - "U2FsdGVkX1/5Y0A7l8xK686rvLsmPviTlna2n3P/ADNm89Ynr1UPZ/Q6bynbe28Y", - "/zWYOB9PAGt+bq1L0z/W2LNHe92HTN/Fwz16aHa98TOsgM3q8tAR4NSqrLZVu1H7" - ] - } -} From 0a246efdab2f5970b0a39ec2b866aa18bb400361 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:59:11 +0100 Subject: [PATCH 33/35] Delete normal-message-metadata.json --- CIP-0020/codesamples/normal-message-metadata.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CIP-0020/codesamples/normal-message-metadata.json diff --git a/CIP-0020/codesamples/normal-message-metadata.json b/CIP-0020/codesamples/normal-message-metadata.json deleted file mode 100644 index 9ff9494fb1..0000000000 --- a/CIP-0020/codesamples/normal-message-metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "674": { - "msg": ["Invoice-No: 123456789","Order-No: 7654321","Email: john@doe.com"] - } -} From 768080b000f86373124476f68deb58938b04f562 Mon Sep 17 00:00:00 2001 From: Martin Lang <47434720+gitmachtl@users.noreply.github.com> Date: Thu, 8 Dec 2022 11:15:01 +0100 Subject: [PATCH 34/35] Updating README with updated Implementors - This update uses the new Header-Scheme, added Implementors and updated some Screenshots --- CIP-0020/README.md | 175 +++++++-------------------------------------- 1 file changed, 25 insertions(+), 150 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index d80d65e2db..c8a85538d7 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -1,15 +1,35 @@ --- CIP: 20 Title: Transaction message/comment metadata -Authors: Martin Lang , Ola Ahlman , Andrew Westberg , Adam Dean -Comments-URI: no comments yet Status: Active -Type: Informational +Category: Metadata +Authors: + - Martin Lang + - Ola Ahlman + - Andrew Westberg +Implementors: + - [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) + - [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/) +Discussions: N/A Created: 2021-06-13 -Updated: 2022-11-29 License: CC-BY-4.0 --- + # Abstract This CIP describes a basic JSON schema to add messages/comments/memos as transaction metadata by using the metadatum label **674**. @@ -89,143 +109,7 @@ The number of theses **message-strings** must be at least one for a single messa  

-# 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": "", - "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. - -  

- -### 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", - "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.** - -  

- -### 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"]` - - 

- -## Some Integration examples (standard/unencrypted) +## Some Integration examples **Ledger Live** is offering a memo field ![image](https://user-images.githubusercontent.com/47434720/204649383-c34ae733-e136-41b8-8fa8-619dde978621.png) @@ -247,13 +131,6 @@ Which results in the original content of the **msg** key: **CNTools**:
![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:"` 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 @@ -264,8 +141,6 @@ an array format, or testing against a string or array format. Updates in the fut 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 ## It is up to the wallet-/display-/receiver-implementor to parse and check the provided metadata. As for the current state, its not possible to have the same label "674" more than once in a cardano transaction. So a check about that can be ignored at the moment. This CIP provides the correct implementation format, the parsing should search for the "674" metadata label and the "msg" key underneath it. There should also be a check, that the provided data within that "msg" key is an array. All other implementations like a missing "msg" key, or a single string instead of an array, should be marked by the display-implementor as "invalid". Additional keys within the "674" label should not affect the parsing of the "msg" key. As written above, we will likely see more entries here in the future like a "version" key for example, so additional keys should not harm the parsing of the "msg" key. From 4e9a0cdfc6768bec1f8111e6056dad4d7390f7f7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 8 Dec 2022 14:10:08 +0100 Subject: [PATCH 35/35] Adjust authors list (remove markdown) + adjust section titles levels. --- CIP-0020/README.md | 89 ++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/CIP-0020/README.md b/CIP-0020/README.md index c8a85538d7..364ef64ce5 100644 --- a/CIP-0020/README.md +++ b/CIP-0020/README.md @@ -8,34 +8,37 @@ Authors: - Ola Ahlman - Andrew Westberg Implementors: - - [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) - - [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/) -Discussions: N/A + - CNTools + - JorManager + - StakePoolOperator Scripts + - Cardanoscan.io + - AdaStat.net + - Eternl Wallet + - CardanoWall + - Nami Wallet + - CNFT + - Cardano Explorer + - SundaeSwap + - Minswap + - MuesliSwap + - DripDropz.io + - Typhon Wallet + - Ledger Live +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/100 + - https://github.com/cardano-foundation/CIPs/pull/394 Created: 2021-06-13 License: CC-BY-4.0 --- +# CIP-0020: Transaction message/comment metadata -# Abstract +## Abstract This CIP describes a basic JSON schema to add messages/comments/memos as transaction metadata by using the metadatum label **674**. Adding **informational text, invoice-numbers or similar** to a transaction on the cardano blockchain. -# Motivation +## Motivation We have the utilities on the cardano blockchain now since the introduction of the "allegra-era". A simple consens about adding messages, comments or memos to transactions is still missing. 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. @@ -59,20 +62,20 @@ Some of the current Tools/Sites/Explorers that have implemented it already: * [Typhon Wallet](https://typhonwallet.io/) * [Ledger Live](https://www.ledger.com/) -# Specification +## Specification The specification for the individual strings follow the general design specification for JSON metadata, which is already implemented and in operation on the cardano blockchain. The used metadatum label is **`"674":`**, this number was choosen because it is the T9 encoding of the string "msg". -The message content has the key **`"msg":`** and consists of an **array** of individual **message-strings**. +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: -``` -{ +``` +{ "674": - { - "msg": - [ + { + "msg": + [ "message-string 1" //Optional: ,"message-string 2","message-string 3" ... ] } @@ -81,11 +84,11 @@ The number of theses **message-strings** must be at least one for a single messa ### Example for a single message/comment/memo: ``` json -{ +{ "674": - { - "msg": - [ + { + "msg": + [ "This is a comment for the transaction xyz, thank you very much!" ] } @@ -94,11 +97,11 @@ The number of theses **message-strings** must be at least one for a single messa ### Example for multiple messages/comments/memos: ``` json -{ +{ "674": - { - "msg": - [ + { + "msg": + [ "Invoice-No: 1234567890", "Customer-No: 555-1234", "P.S.: i will shop again at your store :-)" @@ -109,7 +112,7 @@ The number of theses **message-strings** must be at least one for a single messa  

-## Some Integration examples +### Some Integration examples **Ledger Live** is offering a memo field ![image](https://user-images.githubusercontent.com/47434720/204649383-c34ae733-e136-41b8-8fa8-619dde978621.png) @@ -131,21 +134,21 @@ The number of theses **message-strings** must be at least one for a single messa **CNTools**:
![image](https://user-images.githubusercontent.com/47434720/130353491-fc0f3a69-1937-4e72-b680-c04cc069b5c4.png) - -# Rationale + +## 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, 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 +### 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. - -## Handling ill-formed 674 metadata ## -It is up to the wallet-/display-/receiver-implementor to parse and check the provided metadata. As for the current state, its not possible to have the same label "674" more than once in a cardano transaction. So a check about that can be ignored at the moment. This CIP provides the correct implementation format, the parsing should search for the "674" metadata label and the "msg" key underneath it. There should also be a check, that the provided data within that "msg" key is an array. All other implementations like a missing "msg" key, or a single string instead of an array, should be marked by the display-implementor as "invalid". Additional keys within the "674" label should not affect the parsing of the "msg" key. As written above, we will likely see more entries here in the future like a "version" key for example, so additional keys should not harm the parsing of the "msg" key. +### Handling ill-formed 674 metadata + +It is up to the wallet-/display-/receiver-implementor to parse and check the provided metadata. As for the current state, its not possible to have the same label "674" more than once in a cardano transaction. So a check about that can be ignored at the moment. This CIP provides the correct implementation format, the parsing should search for the "674" metadata label and the "msg" key underneath it. There should also be a check, that the provided data within that "msg" key is an array. All other implementations like a missing "msg" key, or a single string instead of an array, should be marked by the display-implementor as "invalid". Additional keys within the "674" label should not affect the parsing of the "msg" key. As written above, we will likely see more entries here in the future like a "version" key for example, so additional keys should not harm the parsing of the "msg" key. -## Implementation conclusion ## +### Implementation conclusion A transaction message should be considered valid if the following apply: @@ -164,6 +167,6 @@ _Optional to consider for the implementer:_ The implementation format in this CIP should be the ground base for transaction messages/comments/memos and should be respected by creator-/sender-implementations as well as in wallet-/receiver-/display-implementations. -# Copyright +## Copyright This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode)