# ![](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square) Keystore **Authors(s):** - [whyrusleeping](github.com/whyrusleeping) - [Hector Sanjuan](github.com/hsanjuan) **Abstract** This spec provides definitions and operations for the keystore feature in IPFS. # Table of Contents - [Goals](#goals) - [Planned Implementation](#planned-implementation) - [Key storage](#key-storage) - [Interface](#interface) - [Code changes and additions](#code-changes-and-additions) - [Structures](#structures) ## Goals To have a secure, simple and user-friendly way of storing and managing keys for use by ipfs. As well as the ability to share these keys, encrypt, decrypt, sign and verify data. ## Planned Implementation ### Key storage Storage layout and format is defined in the [`repository_fs`](repository_fs.md) part of the spec. ### Interface #### ipfs key ``` USAGE ipfs key - Create and list IPNS name keypairs ipfs key 'ipfs key gen' generates a new keypair for usage with IPNS and 'ipfs name publish'. > ipfs key gen --type=rsa --size=2048 mykey > ipfs name publish --key=mykey QmSomeHash 'ipfs key list' lists the available keys. > ipfs key list self mykey SUBCOMMANDS ipfs key export - Export a keypair ipfs key gen - Create a new keypair ipfs key import - Import a key and prints imported key id ipfs key list - List all local keypairs. ipfs key rename - Rename a keypair. ipfs key rm ... - Remove a keypair. ipfs key rotate - Rotates the IPFS identity. For more information about each command, use: 'ipfs key --help' ``` #### ipfs crypt **NOTE:** as of 2023 Q4, `ipfs crypt` commands are not implemented yet. ``` ipfs crypt - Perform cryptographic operations using ipfs keypairs SUBCOMMANDS: ipfs crypt sign - Generates a signature for the given data with a specified key ipfs crypt verify - Verify that the given data and signature match ipfs crypt encrypt - Encrypt the given data ipfs crypt decrypt - Decrypt the given data DESCRIPTION: `ipfs crypt` is a command used to perform various cryptographic operations using ipfs keypairs, including: signing, verifying, encrypting and decrypting. ``` #### Some subcommands: ##### ipfs key Gen ``` USAGE ipfs key gen - Create a new keypair SYNOPSIS ipfs key gen [--type= | -t] [--size= | -s] [--ipns-base=] [--] ARGUMENTS - name of key to create OPTIONS -t, --type string - type of the key to create: rsa, ed25519. Default: ed25519. -s, --size int - size of the key to generate. --ipns-base string - Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. ``` * * * ##### Key Send ``` USAGE ipfs key - Create and list IPNS name keypairs SYNOPSIS ipfs key DESCRIPTION 'ipfs key gen' generates a new keypair for usage with IPNS and 'ipfs name publish'. > ipfs key gen --type=rsa --size=2048 mykey > ipfs name publish --key=mykey QmSomeHash 'ipfs key list' lists the available keys. > ipfs key list self mykey SUBCOMMANDS ipfs key export - Export a keypair ipfs key gen - Create a new keypair ipfs key import - Import a key and prints imported key id ipfs key list - List all local keypairs. ipfs key rename - Rename a keypair. ipfs key rm ... - Remove a keypair. ipfs key rotate - Rotates the IPFS identity. For more information about each command, use: 'ipfs key --help' ``` ##### Comments: Ensure that the user knows the implications of sending a key. * * * ##### Crypt Encrypt ``` ipfs crypt encrypt - Encrypt the given data with a specified key ARGUMENTS: data - The filename of the data to be encrypted ("-" for stdin) OPTIONS: -k, -key string - The name of the key to use for encryption (default: localkey) -o, -output string - The name of the output file (default: stdout) -c, -cipher string - The cipher to use for the operation -m, -mode string - The block cipher mode to use for the operation DESCRIPTION: 'ipfs crypt encrypt' is a command used to encrypt data so that only holders of a certain key can read it. ``` ##### Comments: This should probably just operate on raw data and not on DAGs. * * * ##### Other Interface Changes We will also need to make additions to support keys in other commands, these changes are as follows: - `ipfs add` - Support for a `-encrypt-key` option, for block encrypting the file being added with the key - also adds an 'encrypted' node above the root unixfs node - Support for a `-sign-key` option to attach a signature node above the root unixfs node - `ipfs block put` - Support for a `-encrypt-key` option, for encrypting the block before hashing and storing - `ipfs object put` - Support for a `-encrypt-key` option, for encrypting the object before hashing and storing - `ipfs name publish` - Support for a `-key` option to select which keyspace to publish to ### Code changes and additions This sections outlines code organization around this feature. #### Keystore package The fsrepo carries a `keystore` that can be used to load/store keys. The keystore is implemented following this interface: ```go // Keystore provides a key management interface type Keystore interface { // Has returns whether or not a key exist in the Keystore Has(string) (bool, error) // Put stores a key in the Keystore, if a key with the same name already exists, returns ErrKeyExists Put(string, ci.PrivKey) error // Get retrieves a key from the Keystore if it exists, and returns ErrNoSuchKey // otherwise. Get(string) (ci.PrivKey, error) // Delete removes a key from the Keystore Delete(string) error // List returns a list of key identifier List() ([]string, error) } ``` Note: Never store passwords as strings, strings cannot be zeroed out after they are used. using a byte array allows you to write zeroes over the memory so that the users password does not linger in memory. #### Unixfs - new node types, 'encrypted' and 'signed', probably shouldn't be in unixfs, just understood by it - if new node types are not unixfs nodes, special consideration must be given to the interop - DagReader needs to be able to access keystore to seamlessly stream encrypted data we have keys for - also needs to be able to verify signatures #### Importer - DagBuilderHelper needs to be able to encrypt blocks - Dag Nodes should be generated like normal, then encrypted, and their parents should link to the hash of the encrypted node - DagBuilderParams should have extra parameters to accommodate creating a DBH that encrypts the blocks #### New 'Encrypt' package Should contain code for crypto operations on dags. Encryption of dags should work by first generating a symmetric key, and using that key to encrypt all the data. That key should then be encrypted with the public key chosen and stored in the Encrypted DAG structure. Note: One option is to simply add it to the key interface. ### Structures Some tentative mockups (in json) of the new DAG structures for signing and encrypting Signed DAG: ``` { "Links" : [ { "Name":"@content", "Hash":"QmTheContent", } ], "Data": protobuf{ "Type":"Signed DAG", "Signature": "thesignature", "PubKeyID": "QmPubKeyHash", } } ``` Encrypted DAG: ``` { "Links" : [ { "Name":"@content", "Hash":"QmRawEncryptedDag", } ], "Data": protobuf{ "Type":"Encrypted DAG", "PubKeyID": "QmPubKeyHash", "Key": "ephemeral symmetric key, encrypted with public key", } } ```