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: