diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index b7a4baf759c..f2178153455 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -16,10 +16,15 @@ import ( namesys "github.com/ipfs/go-ipfs/namesys" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + + ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) +// The default keypair is 2048-bit RSA const ( nBitsForKeypairDefault = 2048 + keypairTypeDefault = ci.RSA + keypairTypeStrDefault = "rsa" ) var initCmd = &cmds.Command{ @@ -49,6 +54,7 @@ environment variable: }, Options: []cmds.Option{ cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault), + cmds.StringOption("key-type", "k", "Key type (RSA or Ed25519-id)").Default(keypairTypeStrDefault), cmds.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false), cmds.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"), @@ -78,18 +84,35 @@ environment variable: return } - empty, _, err := req.Option("e").Bool() + empty, _, err := req.Option("empty-repo").Bool() if err != nil { res.SetError(err, cmds.ErrNormal) return } - nBitsForKeypair, _, err := req.Option("b").Int() + nBitsForKeypair, _, err := req.Option("bits").Int() if err != nil { res.SetError(err, cmds.ErrNormal) return } + keyTypeStr, _, err := req.Option("key-type").String() + if err != nil { + res.SetError(err, cmds.ErrNormal) + return + } + + var keyType int + switch keyTypeStr { + case "rsa": + keyType = ci.RSA + case "ed25519": + keyType = ci.Ed25519 + default: + res.SetError(fmt.Errorf("unrecognized key-type: %s", keyTypeStr), cmds.ErrNormal) + return + } + var conf *config.Config f := req.Files() @@ -118,7 +141,7 @@ environment variable: profiles = strings.Split(profile, ",") } - if err := doInit(os.Stdout, req.InvocContext().ConfigRoot, empty, nBitsForKeypair, profiles, conf); err != nil { + if err := doInit(os.Stdout, req.InvocContext().ConfigRoot, empty, nBitsForKeypair, keyType, profiles, conf); err != nil { res.SetError(err, cmds.ErrNormal) return } @@ -130,10 +153,10 @@ Reinitializing would overwrite your keys. `) func initWithDefaults(out io.Writer, repoRoot string) error { - return doInit(out, repoRoot, false, nBitsForKeypairDefault, nil, nil) + return doInit(out, repoRoot, false, nBitsForKeypairDefault, keypairTypeDefault, nil, nil) } -func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, confProfiles []string, conf *config.Config) error { +func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair, keyType int, confProfiles []string, conf *config.Config) error { if _, err := fmt.Fprintf(out, "initializing IPFS node at %s\n", repoRoot); err != nil { return err } @@ -148,7 +171,7 @@ func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, con if conf == nil { var err error - conf, err = config.Init(out, nBitsForKeypair) + conf, err = config.Init(out, nBitsForKeypair, keyType) if err != nil { return err } diff --git a/core/core.go b/core/core.go index 40bafabebae..01d228021a0 100644 --- a/core/core.go +++ b/core/core.go @@ -56,6 +56,7 @@ import ( logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58" floodsub "gx/ipfs/QmTm7GoSkSSQPP32bZhvu17oY1AfvPKND6ELUdYAcKuR1j/floodsub" + mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" p2phost "gx/ipfs/QmUwW8jMQDxXhLD2j4EfWqLEMX3MsvyWcWGvJPVDh1aTmu/go-libp2p-host" addrutil "gx/ipfs/QmVJGsPeK3vwtEyyTxpCs47yjBYMmYsAhEouPDF3Gb2eK3/go-addr-util" ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" @@ -759,9 +760,29 @@ func loadPrivateKey(cfg *config.Identity, id peer.ID) (ic.PrivKey, error) { return nil, err } - id2, err := peer.IDFromPrivateKey(sk) + decmh, err := mh.Decode([]byte(id)) if err != nil { - return nil, err + return nil, fmt.Errorf("id was not a valid multihash") + } + + // TODO: this isnt very elegant. Formalize how we want to do this + var id2 peer.ID + switch decmh.Code { + case mh.ID: + if _, ok := sk.(*ic.Ed25519PrivateKey); !ok { + return nil, fmt.Errorf("key embedded peer IDs are only supported for ed25519") + } + id2, err = peer.IDFromEd25519PublicKey(sk.GetPublic()) + if err != nil { + return nil, err + } + case mh.SHA2_256: + id2, err = peer.IDFromPrivateKey(sk) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unsupported peer ID hash: %q", mh.Codes[decmh.Code]) } if id2 != id { diff --git a/repo/config/init.go b/repo/config/init.go index 80923355e5c..65a5886415c 100644 --- a/repo/config/init.go +++ b/repo/config/init.go @@ -10,8 +10,8 @@ import ( ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) -func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { - identity, err := identityConfig(out, nBitsForKeypair) +func Init(out io.Writer, nBitsForKeypair, keyType int) (*Config, error) { + identity, err := identityConfig(out, nBitsForKeypair, keyType) if err != nil { return nil, err } @@ -113,15 +113,24 @@ func DefaultDatastoreConfig() Datastore { } // identityConfig initializes a new identity. -func identityConfig(out io.Writer, nbits int) (Identity, error) { +func identityConfig(out io.Writer, nbits, keyType int) (Identity, error) { // TODO guard higher up ident := Identity{} - if nbits < 1024 { - return ident, errors.New("Bitsize less than 1024 is considered unsafe.") + + switch keyType { + case ci.RSA: + if nbits < 1024 { + return ident, errors.New("Bitsize less than 1024 is considered unsafe for RSA.") + } + + fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) + case ci.Ed25519: + fmt.Fprintf(out, "generating Ed25519 keypair...") + default: + return ident, fmt.Errorf("unrecognized keyType: %d", keyType) } - fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) - sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) + sk, pk, err := ci.GenerateKeyPair(keyType, nbits) if err != nil { return ident, err } @@ -135,11 +144,22 @@ func identityConfig(out io.Writer, nbits int) (Identity, error) { } ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes) - id, err := peer.IDFromPublicKey(pk) + kf := peer.IDFromPublicKey + switch keyType { + case ci.RSA: + kf = peer.IDFromPublicKey + case ci.Ed25519: + kf = peer.IDFromEd25519PublicKey + default: + return ident, fmt.Errorf("unrecognized keyType: %d", keyType) + } + + id, err := kf(pk) if err != nil { return ident, err } ident.PeerID = id.Pretty() + fmt.Fprintf(out, "peer identity: %s\n", ident.PeerID) return ident, nil }