Go-ipfs: import and export ipfs private keys

Created on 17 Sep 2017  Â·  25Comments  Â·  Source: ipfs/go-ipfs

Version information: 0.4.11-rc1-2eb4c861

go-ipfs version: 0.4.11-rc1-2eb4c861
Repo version: 6
System version: amd64/linux
Golang version: go1.8.3

Type: Feature/Bug

Severity: Low

Description: Add functionality to import and export ipfs keys

Please add commands to ipfs in order to be able to export and import (private) keys (à la gpg).

If there is no other suggestion something like ipfs key export <name> and ipfs key import <file> --name=<name> would do. They could possibly be adapted to import/export only the public key.

Reasonable usecase

I use ipns to publish my personal blog, and I'd like to be able to publish to it from more than one machine. Moreover, if my pc break I wouldn't be able to update my blog any more.

Attempt at finding a solution

Searching online I was not able to find a way to export my keys (and ipfs help shows nothing) except https://github.com/tswindell/ipfs_keys_export that apparently does not work since ipfs config Identity.PrivKey gives error Error: cannot show or change private key through API.

Quick solutions?

Apart from implementing these (which I guess may take some time), is there any hack I can now perform to be able to import/export keys? For example, are they saved in a specific file with a specific well behaving format?

help wanted

Most helpful comment

We could add a command for exporting keys that runs entirely offline (never over the api)

All 25 comments

@trenta3 if making publishing keys via ipfs key gen, you can find the files for all your keys in $IPFS_PATH/keystore. The default key is still (unfortuantely) in the config file, we are planning on migrating that out soon so that it becomes available in the same place.

What is the format of the files that are stored in $IPFS_PATH/keystore? Can those files be read with external tools like gpg?

I also wish it would be possible to really import keys (e.g. a ed25519 private key in hex format) that were created using other software and not only be able to copy a key that was created using ipfs key gen.

I would like to back the request. The described use-case is perfectly reasonable IMO.

This should even be possible via the API. Usecase: One implements an App with IPFS as backend storage. End-users should be able to use the app from multiple devices (maybe even mobile). It would be necessary that they are able to sign their content with the same key from all devices.

Key issue here is that we don't want to expose private keys on the API, we already fixed it for key that is contained in the config file as any break in browser request sandboxing means that your keys are exposed to arbitrary websites.

We could add a command for exporting keys that runs entirely offline (never over the api)

I can totally understand that one wouldn't want the ability to extract existing keys over the API.

But it _should_ be possible to create a key with the API and have that newly created key returned (as a result of the creation - that one time just when it got created) in a format that can be imported on another machine later.

Consider the usecase of implementing an App with IPFS as backend storage. With create-and-return keys apps can use the API to create keys for themselves to keep track of dynamic content. And the key could e.g. be kept by a browser extension synced with other browsers allowing the user to modify dynamic content.

That's not a bad idea. :+1:

On Sun, Nov 19, 2017, 1:53 PM Peter Valdemar Mørch notifications@github.com
wrote:

I can totally understand that one wouldn't want the ability to extract
existing keys over the API.

But it should be possible to create a key with the API and have that
newly created key returned (as a result of the creation - that one time
just when it got created) in a format that can be imported on another
machine later.

Consider the usecase of implementing an App with IPFS as backend storage.
With create-and-return keys apps can the API to create keys for themselves
to keep track of dynamic content. And the key could e.g. be kept by a
browser extension synced with other browsers allowing the user to modify
dynamic content.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/ipfs/go-ipfs/issues/4240#issuecomment-345552901, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ABL4HLOB4oO9NNKQ8ynJlTNyy7wiXGP-ks5s4KNNgaJpZM4PaNUc
.

It seems that @pruflyos's question was not answered: what is the format for the files in ~/.ipfs/keystore?
What is the most convenient way to access them? is it possible with openssl, gpg?

@Stebalien Thanks for the pointer - unfortunately I don't know go so the barrier to entry is a bit too high for me.

Is there an example / basic recipe to do sign/verify operations with the keys in the keystore?

Context: I am building a distributed app (in Python) on top of IPFS, and it makes a lot of sense to use the IPFS identities for the nodes. All I need is a way to 1) generate a signature; 2) verify a signature.

I have seen command-line versions proposed in the past (ipfs key sign, ipfs key verify), but I cannot find any concrete implementation.

If you're only interested in the IPFS APIhttps://github.com/ipfs/specs/tree/master/keystore, Author[s]: @whyrusleeping.

From a quick look into it, also never used Go-Lang, so maybe some errors:

I can see they use RSA, EC(curve=Ed25519),EC(curve=Secp256k1), check var:KeyTypes, source:key.go file.

Doing a verify or sign search in the repository, you can find test code function:testKeySignature, source:key_test.go.

The above uses mainly key.go.

File: key.go in-topic related Interfaces:
PrivKey(includes the above Key type, has a Sign and GetPublic methods)
Pubkey(includes the above Key type, has a Verify methods)

Under go-libp2p-crypto/pb/ you can see KeyType DataType, with the PublicKey and PrivateKey structs.

Each type of cipher has a file with corresponding name with encryption, decryption, signing and veryfying methods if you have curiosity.

The raw implementation of the signatures and verifications used above:
-Ed25519:https://github.com/agl/ed25519/
-Secp256k1:https://github.com/btcsuite/btcd/tree/master/btcec;
-RSA:https://golang.org/pkg/crypto/, Go-Lang package;

I also saw they had a JavaScript version but didn't look into it:
https://github.com/libp2p/js-libp2p-crypto

@AndreaCensi

Is there an example / basic recipe to do sign/verify operations with the keys in the keystore?

Sorry, I missed your response. We actually use protobufs to store them (the protobufs are in the pb folder in that directory). Most commonly used languages have protobuf libraries.

When actually serializing the keys into the Data field of the protobuf, we do so as follows:

  • Ed25519: We concatenate the private key with the public key. Unfortunately, I don't know the actual format of the underlying keys as @pedroliveira95 said, we use https://github.com/agl/ed25519/).
  • RSA: We use a DER-encoded PKIX format (standard key format).
  • Secp256k1: we use RFC 5915 (I think?).

I'm not sure this will help but I'm seeing the following with [email protected] (repo version 7) in the ~/.ipfs/config file:

{
  "Identity": {
    "PeerID": "Qmbjna...",
    "PrivKey": "RHwz3..."
  },
  "Datastore": { ... 

It appears that "PrivKey" may be what you are looking for.

@angleman ~/.ipfs/config only contains the identity key of the local IPFS node.
However, this issue is about importing the keys for IPNS names. See ipfs key --help for details.
_I would update the title of this issue to be more specific if I could._

@Stebalien thoughts on adding import / export to go-ipfs?
Would it be enough to exclude self and limit export to keys created via API (as suggested in https://github.com/ipfs/go-ipfs/issues/4240#issuecomment-345552901)? Maybe we could add an opt-in flag to key gen that marks newly created key key as "safe to export".

@satazor mentioned they will need them for IDM Wallet UI (ipfs-shipyard/nomios-web).

I checked and we have a discrepancy between go-ipfs and js-ipfs right now.
Both js-ipfs and interface-js-ipfs-core list key import and key export commands:

So, we should totally allow import. As for _export_, I'm fine with export as a _local_ command but I'm concerned about supporting it via the API.

@satazor mentioned they will need them for IDM Wallet UI (ipfs-shipyard/nomios-web).

Do they really need _export_?

@Stebalien We don't need the export. We are using:

  • .dag.get
  • .dag.put
  • .name.resolve
  • .name.publish
  • .key.list
  • .key.import
  • .key.rm

You may check the code here: https://github.com/ipfs-shipyard/js-did-ipid/blob/master/src/index.js

Hope that helps!

Use mnemonic phrases, it's become pretty standard for handling PK's with blockchains and is easily transportable. The only issue is RSA keys which due to their bit sizes produce massive mnemonic phrases. Could always just hex encode and then feed that into a mnemonic phrase generator to reduce size

I've been using a mnemonic phrase exporter for ipfs keys in prod for ~1yr and its been working quite well. See here for an example.

I think this is really important. I've been hesitant to try out ipfs because if I actually started using it for publishing, losing my private key would mean starting over from scratch. A backup story other than "copy your whole ipfs store" is necessary I think.

What about just backing up keystore or specific files from there? Whether that directory structure is guaranteed or not, I think there's another issue here that if you need to restore and the newest version has a different model version + needs a migration you'll have to create a dummy .ipfs store of the old version to put your key in to do the migration...

Do they really need _export_?

Export is needed for people who have generated their keys before this feature was implemented and want to back them up I think.

The concern here is adding an API (exposed over the HTTP endpoint) to export the keys. I guess we _could_ add a local-only command that would run on the local repo. However, that could lead to some inconsistent behavior (e.g., when using a remote daemon).

If you just want to backup your keys, copy "config" and "keystore" from your IPFS repo. Your main private key is stored in "Identity.PrivKey" (base64 encoded) in your "config" file. All other keys are stored in flat files in the "keystore".

What would be the restore procedure for that? init won't work if you only have those files and the data format may have changed since, right?

You'd have to copy the files back:

  1. Copy the Identity section of your old config over the identity section in the new config in the new repo.
  2. Replace the new repo's keystore with the old repo's keystore.

You're right, the data format may have changed but this is something that'll be explicitly called out in release notes (and is pretty uncommon). If the data format has changed, you'd need to create a new repo with the old keys and the old go-ipfs version, then upgrade go-ipfs (running the repo migrations). That will automatically migrate the keys.

If you'd like to implement ipfs key import/export, go ahead. We'll just have to restrict export to only running on the local node and not over the API.

Great, just wanted to make sure my understanding was correct here. I opened https://github.com/ipfs/interface-go-ipfs-core/pull/64 since I think that's the first change that will need to happen, although if you have pointers about the order of projects in which changes need to be made that would be helpful.

This is a bit of a special case, I wouldn't implement them on the CoreAPI.

For now, I'd implement it directly in core/commands/keystore.go. Instead of calling cmdenv.GetApi to get a CoreAPI instance, you'll call cmdenv.GetConfigRoot. From there, you can:

  1. Read the config.
  2. Directly open the repo (with repo/fsrepo.Open) to access the keystore.

Perfect, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jonchoi picture jonchoi  Â·  3Comments

whyrusleeping picture whyrusleeping  Â·  4Comments

slrslr picture slrslr  Â·  3Comments

magik6k picture magik6k  Â·  3Comments

djdv picture djdv  Â·  3Comments