@cryptotaxi247 / kubo / commits / aa5a34a6d

add init command to generate crypto keys

Jeromy committed Sep 2, 2014 at 12:58 UTC aa5a34a6d175777cdb61c3d81e8e02753fd4da0b
5 files changed +137 -14
cmd/ipfs/init.go new
+81
@@ -0,0 +1,81 @@
1 +package main
2 +
3 +import (
4 + "encoding/base64"
5 + "errors"
6 + "os"
7 +
8 + "github.com/gonuts/flag"
9 + "github.com/jbenet/commander"
10 + config "github.com/jbenet/go-ipfs/config"
11 + "github.com/jbenet/go-ipfs/identify"
12 + u "github.com/jbenet/go-ipfs/util"
13 +)
14 +
15 +var cmdIpfsInit = &commander.Command{
16 + UsageLine: "init",
17 + Short: "Initialize ipfs local configuration",
18 + Long: `ipfs init
19 +
20 + Initializes ipfs configuration files and generates a
21 + new keypair.
22 +`,
23 + Run: initCmd,
24 + Flag: *flag.NewFlagSet("ipfs-init", flag.ExitOnError),
25 +}
26 +
27 +func init() {
28 + cmdIpfsInit.Flag.Int("b", 4096, "number of bits for keypair")
29 + cmdIpfsInit.Flag.String("p", "", "passphrase for encrypting keys")
30 + cmdIpfsInit.Flag.Bool("f", false, "force overwrite of existing config")
31 +}
32 +
33 +func initCmd(c *commander.Command, inp []string) error {
34 + _, err := os.Lstat(config.DefaultConfigFilePath)
35 + force := c.Flag.Lookup("f").Value.Get().(bool)
36 + if err != nil && !force {
37 + return errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)")
38 + }
39 + cfg := new(config.Config)
40 +
41 + cfg.Datastore = new(config.Datastore)
42 + dspath, err := u.TildeExpansion("~/.go-ipfs/datastore")
43 + if err != nil {
44 + return err
45 + }
46 + cfg.Datastore.Path = dspath
47 + cfg.Datastore.Type = "leveldb"
48 +
49 + cfg.Identity = new(config.Identity)
50 + // This needs thought
51 + // cfg.Identity.Address = ""
52 +
53 + nbits := c.Flag.Lookup("b").Value.Get().(int)
54 + if nbits < 1024 {
55 + return errors.New("Bitsize less than 1024 is considered unsafe.")
56 + }
57 + kp, err := identify.GenKeypair(nbits)
58 + if err != nil {
59 + return err
60 + }
61 +
62 + // pretend to encrypt key, then store it unencrypted
63 + enckey := base64.StdEncoding.EncodeToString(kp.PrivBytes())
64 + cfg.Identity.PrivKey = enckey
65 +
66 + id, err := kp.ID()
67 + if err != nil {
68 + return err
69 + }
70 + cfg.Identity.PeerID = id.Pretty()
71 +
72 + path, err := u.TildeExpansion(config.DefaultConfigFilePath)
73 + if err != nil {
74 + return err
75 + }
76 + err = config.WriteConfigFile(path, cfg)
77 + if err != nil {
78 + return err
79 + }
80 + return nil
81 +}
cmd/ipfs/ipfs.go
+1
@@ -46,6 +46,7 @@ Use "ipfs help <command>" for more information about a command.
46 cmdIpfsVersion,
47 cmdIpfsCommands,
48 cmdIpfsMount,
49 + cmdIpfsInit,
50 },
51 Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
52 }
config/config.go
+21 -8
@@ -1,6 +1,10 @@
1 package config
2
3 import (
4 + "crypto"
5 + "crypto/x509"
6 + "encoding/base64"
7 + "errors"
8 "os"
9
10 u "github.com/jbenet/go-ipfs/util"
@@ -9,6 +13,7 @@ import (
13 // Identity tracks the configuration of the local node's identity.
14 type Identity struct {
15 PeerID string
16 + PrivKey string
17 Address string
18 }
19
@@ -29,8 +34,8 @@ type Config struct {
34 Peers []*SavedPeer
35 }
36
32 -var defaultConfigFilePath = "~/.go-ipfs/config"
33 -var defaultConfigFile = `{
37 +var DefaultConfigFilePath = "~/.go-ipfs/config"
38 +var DefaultConfigFile = `{
39 "identity": {},
40 "datastore": {
41 "type": "leveldb",
@@ -39,10 +44,20 @@ var defaultConfigFile = `{
44 }
45 `
46
47 +func (i *Identity) DecodePrivateKey(passphrase string) (crypto.PrivateKey, error) {
48 + pkb, err := base64.StdEncoding.DecodeString(i.PrivKey)
49 + if err != nil {
50 + return nil, err
51 + }
52 +
53 + //pretend to actually decrypt private key
54 + return x509.ParsePKCS1PrivateKey(pkb)
55 +}
56 +
57 // Filename returns the proper tilde expanded config filename.
58 func Filename(filename string) (string, error) {
59 if len(filename) == 0 {
45 - filename = defaultConfigFilePath
60 + filename = DefaultConfigFilePath
61 }
62
63 // tilde expansion on config file
@@ -56,11 +71,9 @@ func Load(filename string) (*Config, error) {
71 return nil, err
72 }
73
59 - // if nothing is there, write first config file.
74 + // if nothing is there, fail. User must run 'ipfs init'
75 if _, err := os.Stat(filename); os.IsNotExist(err) {
61 - if err := WriteFile(filename, []byte(defaultConfigFile)); err != nil {
62 - return nil, err
63 - }
76 + return nil, errors.New("ipfs not initialized, please run 'ipfs init'")
77 }
78
79 var cfg Config
@@ -80,5 +93,5 @@ func Load(filename string) (*Config, error) {
93
94 // Set sets the value of a particular config key
95 func Set(filename, key, value string) error {
83 - return nil
96 + return WriteConfigKey(filename, key, value)
97 }
core/core.go
+22 -6
@@ -1,12 +1,17 @@
1 package core
2
3 import (
4 + "crypto"
5 + "crypto/rsa"
6 + "errors"
7 "fmt"
8
9 ds "github.com/jbenet/datastore.go"
10 + b58 "github.com/jbenet/go-base58"
11 "github.com/jbenet/go-ipfs/bitswap"
12 bserv "github.com/jbenet/go-ipfs/blockservice"
13 config "github.com/jbenet/go-ipfs/config"
14 + "github.com/jbenet/go-ipfs/identify"
15 merkledag "github.com/jbenet/go-ipfs/merkledag"
16 path "github.com/jbenet/go-ipfs/path"
17 peer "github.com/jbenet/go-ipfs/peer"
@@ -98,17 +103,28 @@ func loadBitswap(cfg *config.Config, d ds.Datastore) (*bitswap.BitSwap, error) {
103 return nil, err
104 }
105
106 + pk, err := cfg.Identity.DecodePrivateKey("")
107 + if err != nil {
108 + return nil, err
109 + }
110 +
111 + var pubkey crypto.PublicKey
112 + switch k := pk.(type) {
113 + case *rsa.PrivateKey:
114 + pubkey = &k.PublicKey
115 + default:
116 + return nil, identify.ErrUnsupportedKeyType
117 + }
118 +
119 local := &peer.Peer{
102 - ID: peer.ID(cfg.Identity.PeerID),
120 + ID: peer.ID(b58.Decode(cfg.Identity.PeerID)),
121 Addresses: []*ma.Multiaddr{maddr},
122 + PrivKey: pk,
123 + PubKey: pubkey,
124 }
125
126 if len(local.ID) == 0 {
107 - mh, err := u.Hash([]byte("blah blah blah ID"))
108 - if err != nil {
109 - return nil, err
110 - }
111 - local.ID = peer.ID(mh)
127 + return nil, errors.New("No peer ID in config! (was ipfs init run?)")
128 }
129
130 net := swarm.NewSwarm(local)
identify/identify.go
+12
@@ -16,6 +16,9 @@ import (
16 u "github.com/jbenet/go-ipfs/util"
17 )
18
19 +// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
20 +var ErrUnsupportedKeyType = errors.New("unsupported key type")
21 +
22 // Perform initial communication with this peer to share node ID's and
23 // initiate communication
24 func Handshake(self, remote *peer.Peer, in, out chan []byte) error {
@@ -151,6 +154,15 @@ func (pk *KeyPair) ID() (peer.ID, error) {
154 return peer.ID(hash), nil
155 }
156
157 +func (pk *KeyPair) PrivBytes() []byte {
158 + switch k := pk.Priv.(type) {
159 + case *rsa.PrivateKey:
160 + return x509.MarshalPKCS1PrivateKey(k)
161 + default:
162 + panic("Unsupported private key type.")
163 + }
164 +}
165 +
166 func (kp *KeyPair) Save(dir string) error {
167 switch k := kp.Priv.(type) {
168 case *rsa.PrivateKey: