Skip to content
Snippets Groups Projects

Tx comment encrypt

Open Éloïs requested to merge tx_comment_encrypt into master
All threads resolved!
+ 181
0
# RFC 17: Transaction Comment Encryption
This RFC defines a format for encrypting transaction comments for the case of transactions involving a single issuer key and a single receiver key.
Let `Si` the seed of the issuer and `Pi` its associated ed25519 public key.
Let `Sr` the seed of the receiver and `Pr` its associated ed25519 public key.
## Convert Ed25519 keys to x25519 keys
The first step is to convert the Ed25519 keys into x25519 keys (also called curve25519 keys).
### Convert Ed25519 secret key to x25519 secret key
Use the first 32 bytes of the extended secret key.
The extended secret key is derived from the seed by the NaCl function `crypto_box_seed_keypair`.
Let `Si' = crypto_box_seed_keypair(Si)[..32]`;
### Convert Ed25519 public key to x25519 public key
Use NaCl function `crypto_sign_ed25519_pk_to_curve25519`.
Let `Pr' = crypto_sign_ed25519_pk_to_curve25519(Pr)`
## Generate symmetric encryption key
We use nacl function [crypto_box_beforenm]. Then use scrypt with a random nonce.
Let `R = crypto_box_beforenm(Si', Pr') = crypto_box_beforenm(Sr', Pi')`.
Let `s` be a random salt of 16 bytes.
The symmetric encryption key `k` is obtained as follows:
`k = scrypt(R, s)`
With following parameters for scrypt:
| Parameter | Value |
|:-----------:|:-------:|
|**password** | R |
|**Salt** | s |
|**N** | 1024 |
|**r** | 8 |
|**p** | 1 |
|**dkLen** | message length |
## Encrypt with XOR cipher
Encrypt bit per bit with XOR cipher.
## Serialize encrypted message with meta data
| Metadata | Encrypted Data |
| ------ | -------------- |
| 20 bytes | max. 171 bytes |
### Metadata
| Magic value | Version | Message type | Nonce |
|:-----------:|:-------:|:------------:|:--------:|
| `0x27b6` | `0x01` | 1 byte | 16 bytes |
### Encrypted Data
| Real message length | UTF8 message | Random extra bytes |
|:-------------------:|:------------:|:------------------:|
| 1 byte | Any byte | Any bytes |
The message must be encoded in UTF8.
### Magic value
A constant value that recognizes that the data should be interpreted according to this format.
A possible future format must use a different magic value.
### Version
Future versions of the present format must increment this byte.
### Message type
| Code | Significance |
|:----:|:---------------:|
| 0x00 | For a human |
| 0x01 | For a machine |
### Nonce
An sequence of 16 random bytes to use as scrypt salt
### Real message length
Indicates the real size of the message in bytes. That is, the number of bytes that should be interpreted as an UTF8 string. There may be extra bytes, the extra bytes should be ignored (see section "Random extra bytes").
### Random extra bytes
The presence of extra bytes only serves to hide the real length of the message from outside observers.
There may well be no extra bytes, just as there may be many.
It is recommended to randomly generate a random number of extra bytes to obscure the real length of the message.
## Encoding in transaction document
Encrypted message in encoded in base 64 (without padding) in transaction comment directly (DUBP protocol already accept all base 64 characters).
## Maximum message length
The DUBP protocol allows up to 255 characters in the comment field, so it is possible to encode up to 191 bytes in base64 (without padding).
There are at least 21 bytes of metadata, so the maximum size of a message is **170 bytes**.
## Quickly recognize if a comment fits this format
You can quickly recognize if a comment fits this format with the following regex: `J7YB[0-9a-zA-Z+/]{24,}`
## Encrypt transaction comment (Issuer side)
Let `m` the user message bytes encoded in UTF8.
Let `t` the message type.
1. Generate 16 random bytes and stores them in a byte array `nonce`.
1. Compute `l = m.lenght`
1. Generate a random integer `x` between `0` and `170 - l`
1. Generate `x` random bytes and add them at end of `m`.
1. compute `L = l + x + 1`
1. compute `Si'` and `Pr'`.
1. Create a bytes array `dataToEncrypt` of length `L`
1. Push the byte `l` in `dataToEncrypt`
1. Append `m` to `dataToEncrypt`
1. Compute `R = crypto_box_beforenm(Si', Pr')`
1. Generate symmetric encryption key `k = scrypt(R, salt: nonce, N: 1024, r: 8, p: 1, dkLen: L)`
1. compute `encryptedData = dataToEncrypt ^ k`
1. Create a bytes array `b` of length `L + 20`
1. Fill the three first bytes of `b` with content `0x27b601`
1. Push the byte `t` in `b`
1. Append `nonce` to `b`
1. Append `encryptedData` to `b`
1. Compute `source = base64.encode(b)`
1. Write `source` in a comment field of transaction document
## Decrypt transaction comment (Receiver side)
Let `source` a base64 string read from comment field of a transaction document.
1. Compute `b = base64.decode(source)`
1. Ensure that `b.length >= 3`
1. Ensure that `b[0] = 0x27` and `b[1] = 0xb6` (magic value check)
1. Ensure that `b[2] = 0x01` (version check)
1. Read `t = b[3]`. Depending on the `t` value and your reading context, you can stop here or continue.
1. Ensure that `b.length >= 21`
1. compute `Sr'` and `Pi'`.
1. Compute `R = crypto_box_beforenm(Sr', Pi')`
1. compute `L = b.length - 20`
1. Read `nonce`: the bytes array from `b[4]` to `b[19]`
1. Generate symmetric encryption key `k = scrypt(R, salt: nonce, N: 1024, r: 8, p: 1, dkLen: L)`
1. Read `encryptedMessage`: the bytes array from `b[20]` to `b[b.length -1]`
1. Compute `m = encryptedMessage ^ k`
1. Read `l = m[0]`
1. Ensure that `m.length > l`
1. Interpret bytes `m[1]` to `m[l]` as an UTF8 string
## Example
| Parameter | Value |
| --------- | ----- |
|Sender Public Key| EVfy1VoZwbuN7L69kYiHxeosJLh5azkHV8G6TaSLy94r |
|Sender Seed |0x0c6a15d0004d24a40f6503300d4971032fb057ff7dc229d651683b413c96a216 |
|Receiver Public Key| 8txjWNFZhMJbKPijvnFybeksN1QpKaKJrM4jW8HhnFsX |
|Receiver Seed| 0x214955b558c7793268589e557eda2ab69b5293b73d3907f82c82e12d69c47221 |
|Comment| My taylor is rich ? Isn't it ? Un été 42...|
|Nonce| 0x16740285721adeb10da04106c9eb9e34 |
|Extra Bytes| 0x17968f2f344679fe23ef483a53adcaa18ecd753036dd2cdab1 |
|Scrypt Password| 0xe63c31edb6e9e4fa04142cd73f30423aa7fb09e404fb60f154dcc913a7e3657c|
|XOR Key| 0x691114edf5f3da4f4c04b77842da44a4fa97cd59fee742c98244441897e91532de8bcf883d279d4cf4ab3715014cf417a309c979ee4058613668698e1f0df8edf4ac556868e64f|
|Encrypted comment| J7YBABZ0AoVyGt6xDaBBBsnrnjREXG3NgZKjIyN2lxEx+jbNmf/tZt6uMaelMGRx48kqEovl70uUU17l1J8FOy9i44EsJv0/l757jn5SOiPVrHYggZxjtUQ8/g|
[crypto_box_beforenm]: https://nacl.cr.yp.to/box.html
[Null character]: https://en.wikipedia.org/wiki/Null_character
[XOR cipher]: https://en.wikipedia.org/wiki/XOR_cipher
Loading