Skip to content
Snippets Groups Projects

Tx comment encrypt

Open Éloïs requested to merge tx_comment_encrypt into master
All threads resolved!
+ 144
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 ed25519 secret key of the issuer and `Pi` its associated ed25519 public key.
 
Let `Sr` the ed25519 secret key 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_sign_ed25519_seed_keypair`.
 
 
Let `Si' = 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 symetric 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:
 
 
```txt
 
password = R
 
Salt = s
 
N = 1024
 
r = 12
 
p = 1
 
dkLen = message length
 
```
 
 
## Encrypt with XOR cipher
 
 
Encrypt bit per bit with XOR cipher.
 
 
## Serialize encrypted message with meta data
 
 
| Magic value | Version | Message type | Salt | Real message length | Encrypted UTF8 message | Random extra bytes |
 
|:-----------:|:-------:|:------------:|:--------:|:-------------------:|:----------------------:|:------------------:|
 
| `0x27b6` | `0x01` | 1 byte | 16 bytes | 1 byte (encrypted) | Any bytes | 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 |
 
 
### 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 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**.
 
 
## Encrypt transaction comment (Issuer side)
 
 
Let `m` the user message bytes encoded in UTF8.
 
Let `t` the message type.
 
 
1. Generate 12 random bytes a 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. compute `Si'` and `Pr'`.
 
1. Compute `R = crypto_box_beforenm(Si', Pr')`
 
1. Generate symmetric encryption key `k = scrypt(R, salt, N: 1024, r: 12, p: 1, dkLen: L)`
 
1. compute `encryptedMessage = m ^ 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. Push the byte `l` in `b`
 
1. Append `m` to `b`
 
1. Compute `source = base64.encode(b)`
 
1. Write `source` in a comment field of trasaction 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. Let `salt` a bytes array from `b[4]` to `b[19]`
 
1. Generate symmetric encryption key `k = scrypt(R, salt, N: 1024, r: 12, p: 1, dkLen: L)`
 
1. Let `encryptedMessage` a 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
 
 
[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