diff --git a/README.md b/README.md index ccca69ed32668754c70ac5a1bc116a2ba0f5240f..72f1e2aa5bdd445ffe856b91ed83530cb5294491 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ All documents should be implementation agnostic, as specific documentations shou * RFC_0003: [GraphQL API for Duniter Clients](https://git.duniter.org/nodes/common/doc/blob/graphql_api_rfc/rfc/0003%20RFC%20GraphQL%20API%20for%20Duniter%20Clients.md) * RFC_0006: [DUniter Network Protocol V2](https://git.duniter.org/nodes/common/doc/blob/ws2p_v2/rfc/0006_ws2p_v2.md) * RFC_0011: [Public Key Secure Transport Layer V1](https://git.duniter.org/nodes/common/doc/blob/ws2p_v2/rfc/0011_pkstl_v1.md) +* RFC_0012: [Authentication File Format](https://git.duniter.org/nodes/common/doc/blob/authentication_file_format/rfc/0012_authentication_file_format_v1.md) ### Discontinued RFCs diff --git a/rfc/0012_authentication_file_format_v1.md b/rfc/0012_authentication_file_format_v1.md new file mode 100644 index 0000000000000000000000000000000000000000..1cb6309a62d42bce6c4c3e2df38043d991e96336 --- /dev/null +++ b/rfc/0012_authentication_file_format_v1.md @@ -0,0 +1,143 @@ +```txt +RFC: 12 +Title: RFC Format +Type: Convention +Status: Draft +Author: vit +Created: 2020-02-12 +Last edited: 2020-02-12 +License: GPL-3 +``` + +# Authentication File Format + +This document serves as a reference for a interoperable authentication file format. + +## File format extension + +Cesium client use the ".duniterkey" extension. So for now, the official extension is `.duniterkey`. + +## Text File Format + +This format is inspired by [the Yaml format](https://yaml.org/spec/1.2/spec.html) for human readability. + +The charset is utf-8 and the newline are unix style (\n). + +So it is a yaml formatted file containing root fields of the form: + +```yaml +Type: string +Version: int +data_field_1: data_value_1 +[data_field_n: data_value_n] +``` + +## Header fields + +The first two fields are the header of the file. Their purpose is to know how to treat the following data fields. + +### Type field + +The first field is the `Type` field. Its value is a string id identifying the type of data in the file. + +Recognized values are: + +* `PubSec` +* `WIF` +* `EWIF` + +### Version field + +The second field is the `Version` field. Its value is an integer specifying a version for the following data. + +## Data fields + +After the header fields come the data fields. This number and the name of the fields depend on the type of data. + +### PubSec fields + +The PubSec fields are as follow: + +```yaml +Type: PubSec +Version: 1 +pub: base58(public_key_bytes) +sec: base58(secret_key_bytes) +``` +`public_key_bytes` is the public key in bytes. + +`secret_key_bytes` is the secret key in bytes. + +### WIF fields + +The WIF fields are as follow: + +```yaml +Type: WIF +Version: 1 +Data: base58(data_bytes) +``` +Where +```shell script +data_bytes = format_byte + seed_bytes + checksum_bytes +``` +Where +```shell script +format_byte = \x01 +checksum_bytes = sha256(sha256(format_byte + seed_bytes))[0:2] +``` +`format_byte` is one byte with value 1 for the WIF format. + +`seed_bytes` is the seed in bytes of the key pair. + +`checksum_bytes` are the two first bytes of a two pass sha256 hash of the `format_byte` concatenated to the `seed_bytes`. + +### EWIF fields + +The EWIF fields are as follow: + +```yaml +Type: EWIF +Version: 1 +Data: base58(seed_bytes + checksum_bytes) +``` +Where +```shell script +checksum_bytes = sha256(sha256(seed_bytes))[0:2] +``` +Where +```shell script +seed_bytes = \x02 + salt + encrypted_half_1 + encrypted_half_2 +``` +Where +```shell script +salt = sha256(sha256(pubkey_bytes))[0:4] + +password_bytes = bytes(password_utf8_string) + +scrypt_seed = scrypt(password_bytes, salt, n=16384, r=8, p=8, length=64) + +derived_half_1 = scrypt_seed[0:32] +derived_half_2 = scrypt_seed[32:64] + +seed1_xor_derived_half_1a = bytes(xor_bytes(original_seed_bytes[0:16], derived_half_1[0:16])) +seed2_xor_derived_half_1b = bytes(xor_bytes(original_seed_bytes[16:32], derived_half_1[16:32])) + +encrypted_half_1 = aes256.encrypt(seed1_xor_derived_half_1a, key=derived_half_2) +encrypted_half_2 = aes256.encrypt(seed2_xor_derived_half_1b, key=derived_half_2) + +seed_bytes = \x02 + salt + encrypted_half_1 + encrypted_half_2 +``` +`password_utf8_string` is the password string in utf-8 used to encrypt the seed. + +`pubkey_bytes` is the public key in bytes used to create the `salt` value. + +`original_seed_bytes` is the original seed in bytes of the key pair. + +This document can be completed and improved by Tortue document: + +https://tmp.tednet.fr/paperwallet/AddressFormat.html + +Thanks to him for his work. + +End of document \ No newline at end of file