create new crypto package and make rest of repo use it
Jeromy committed
Sep 3, 2014 at 20:15 UTC
4b97f1f27005fc5e583b0343c53703a22af4753c
10 files changed
+349
-109
cmd/ipfs/init.go
+10
-5
@@ -8,7 +8,8 @@ import (
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"
11
+ ci "github.com/jbenet/go-ipfs/crypto"
12
+ identify "github.com/jbenet/go-ipfs/identify"
13
u "github.com/jbenet/go-ipfs/util"
14
)
15
@@ -54,16 +55,20 @@ func initCmd(c *commander.Command, inp []string) error {
55
if nbits < 1024 {
56
return errors.New("Bitsize less than 1024 is considered unsafe.")
57
}
57
- kp, err := identify.GenKeypair(nbits)
58
+
59
+ sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
60
if err != nil {
61
return err
62
}
63
64
// pretend to encrypt key, then store it unencrypted
63
- enckey := base64.StdEncoding.EncodeToString(kp.PrivBytes())
64
- cfg.Identity.PrivKey = enckey
65
+ skbytes, err := sk.Bytes()
66
+ if err != nil {
67
+ return err
68
+ }
69
+ cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes)
70
66
- id, err := kp.ID()
71
+ id, err := identify.IdFromPubKey(pk)
72
if err != nil {
73
return err
74
}
core/core.go
+8
-12
@@ -1,8 +1,7 @@
1
package core
2
3
import (
4
- "crypto"
5
- "crypto/rsa"
4
+ "encoding/base64"
5
"errors"
6
"fmt"
7
@@ -11,7 +10,7 @@ import (
10
"github.com/jbenet/go-ipfs/bitswap"
11
bserv "github.com/jbenet/go-ipfs/blockservice"
12
config "github.com/jbenet/go-ipfs/config"
14
- "github.com/jbenet/go-ipfs/identify"
13
+ ci "github.com/jbenet/go-ipfs/crypto"
14
merkledag "github.com/jbenet/go-ipfs/merkledag"
15
path "github.com/jbenet/go-ipfs/path"
16
peer "github.com/jbenet/go-ipfs/peer"
@@ -103,24 +102,21 @@ func loadBitswap(cfg *config.Config, d ds.Datastore) (*bitswap.BitSwap, error) {
102
return nil, err
103
}
104
106
- pk, err := cfg.Identity.DecodePrivateKey("")
105
+ skb, err := base64.StdEncoding.DecodeString(cfg.Identity.PrivKey)
106
if err != nil {
107
return nil, err
108
}
109
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
110
+ sk, err := ci.UnmarshalPrivateKey(skb)
111
+ if err != nil {
112
+ return nil, err
113
}
114
115
local := &peer.Peer{
116
ID: peer.ID(b58.Decode(cfg.Identity.PeerID)),
117
Addresses: []*ma.Multiaddr{maddr},
122
- PrivKey: pk,
123
- PubKey: pubkey,
118
+ PrivKey: sk,
119
+ PubKey: sk.GetPublic(),
120
}
121
122
if len(local.ID) == 0 {
crypto/encode.pb.go
new
+104
@@ -0,0 +1,104 @@
1
+// Code generated by protoc-gen-go.
2
+// source: encode.proto
3
+// DO NOT EDIT!
4
+
5
+/*
6
+Package crypto is a generated protocol buffer package.
7
+
8
+It is generated from these files:
9
+ encode.proto
10
+
11
+It has these top-level messages:
12
+ PBPublicKey
13
+ PBPrivateKey
14
+*/
15
+package crypto
16
+
17
+import proto "code.google.com/p/goprotobuf/proto"
18
+import math "math"
19
+
20
+// Reference imports to suppress errors if they are not otherwise used.
21
+var _ = proto.Marshal
22
+var _ = math.Inf
23
+
24
+type KeyType int32
25
+
26
+const (
27
+ KeyType_RSA KeyType = 0
28
+)
29
+
30
+var KeyType_name = map[int32]string{
31
+ 0: "RSA",
32
+}
33
+var KeyType_value = map[string]int32{
34
+ "RSA": 0,
35
+}
36
+
37
+func (x KeyType) Enum() *KeyType {
38
+ p := new(KeyType)
39
+ *p = x
40
+ return p
41
+}
42
+func (x KeyType) String() string {
43
+ return proto.EnumName(KeyType_name, int32(x))
44
+}
45
+func (x *KeyType) UnmarshalJSON(data []byte) error {
46
+ value, err := proto.UnmarshalJSONEnum(KeyType_value, data, "KeyType")
47
+ if err != nil {
48
+ return err
49
+ }
50
+ *x = KeyType(value)
51
+ return nil
52
+}
53
+
54
+type PBPublicKey struct {
55
+ Type *KeyType `protobuf:"varint,1,req,enum=crypto.KeyType" json:"Type,omitempty"`
56
+ Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
57
+ XXX_unrecognized []byte `json:"-"`
58
+}
59
+
60
+func (m *PBPublicKey) Reset() { *m = PBPublicKey{} }
61
+func (m *PBPublicKey) String() string { return proto.CompactTextString(m) }
62
+func (*PBPublicKey) ProtoMessage() {}
63
+
64
+func (m *PBPublicKey) GetType() KeyType {
65
+ if m != nil && m.Type != nil {
66
+ return *m.Type
67
+ }
68
+ return KeyType_RSA
69
+}
70
+
71
+func (m *PBPublicKey) GetData() []byte {
72
+ if m != nil {
73
+ return m.Data
74
+ }
75
+ return nil
76
+}
77
+
78
+type PBPrivateKey struct {
79
+ Type *KeyType `protobuf:"varint,1,req,enum=crypto.KeyType" json:"Type,omitempty"`
80
+ Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
81
+ XXX_unrecognized []byte `json:"-"`
82
+}
83
+
84
+func (m *PBPrivateKey) Reset() { *m = PBPrivateKey{} }
85
+func (m *PBPrivateKey) String() string { return proto.CompactTextString(m) }
86
+func (*PBPrivateKey) ProtoMessage() {}
87
+
88
+func (m *PBPrivateKey) GetType() KeyType {
89
+ if m != nil && m.Type != nil {
90
+ return *m.Type
91
+ }
92
+ return KeyType_RSA
93
+}
94
+
95
+func (m *PBPrivateKey) GetData() []byte {
96
+ if m != nil {
97
+ return m.Data
98
+ }
99
+ return nil
100
+}
101
+
102
+func init() {
103
+ proto.RegisterEnum("crypto.KeyType", KeyType_name, KeyType_value)
104
+}
crypto/encode.proto
new
+15
@@ -0,0 +1,15 @@
1
+package crypto;
2
+
3
+enum KeyType {
4
+ RSA = 0;
5
+}
6
+
7
+message PBPublicKey {
8
+ required KeyType Type = 1;
9
+ required bytes Data = 2;
10
+}
11
+
12
+message PBPrivateKey {
13
+ required KeyType Type = 1;
14
+ required bytes Data = 2;
15
+}
crypto/key.go
new
+88
@@ -0,0 +1,88 @@
1
+package crypto
2
+
3
+import (
4
+ "errors"
5
+
6
+ "crypto/rand"
7
+ "crypto/rsa"
8
+
9
+ "code.google.com/p/goprotobuf/proto"
10
+)
11
+
12
+var ErrBadKeyType = errors.New("invalid or unsupported key type")
13
+
14
+const (
15
+ RSA = iota
16
+)
17
+
18
+type PrivKey interface {
19
+ // Cryptographically sign the given bytes
20
+ Sign([]byte) ([]byte, error)
21
+
22
+ // Decrypt a message encrypted with this keys public key
23
+ Decrypt([]byte) ([]byte, error)
24
+
25
+ // Return a public key paired with this private key
26
+ GetPublic() PubKey
27
+
28
+ // Generate a secret string of bytes
29
+ GenSecret() []byte
30
+
31
+ // Bytes returns a serialized, storeable representation of this key
32
+ Bytes() ([]byte, error)
33
+}
34
+
35
+type PubKey interface {
36
+ // Verify that 'sig' is the signed hash of 'data'
37
+ Verify(data []byte, sig []byte) (bool, error)
38
+
39
+ // Encrypt the given data with the public key
40
+ Encrypt([]byte) ([]byte, error)
41
+
42
+ // Bytes returns a serialized, storeable representation of this key
43
+ Bytes() ([]byte, error)
44
+}
45
+
46
+func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
47
+ switch typ {
48
+ case RSA:
49
+ priv, err := rsa.GenerateKey(rand.Reader, bits)
50
+ if err != nil {
51
+ return nil, nil, err
52
+ }
53
+ pk := &priv.PublicKey
54
+ return &RsaPrivateKey{priv}, &RsaPublicKey{pk}, nil
55
+ default:
56
+ return nil, nil, ErrBadKeyType
57
+ }
58
+}
59
+
60
+func UnmarshalPublicKey(data []byte) (PubKey, error) {
61
+ pmes := new(PBPublicKey)
62
+ err := proto.Unmarshal(data, pmes)
63
+ if err != nil {
64
+ return nil, err
65
+ }
66
+
67
+ switch pmes.GetType() {
68
+ case KeyType_RSA:
69
+ return UnmarshalRsaPublicKey(pmes.GetData())
70
+ default:
71
+ return nil, ErrBadKeyType
72
+ }
73
+}
74
+
75
+func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
76
+ pmes := new(PBPrivateKey)
77
+ err := proto.Unmarshal(data, pmes)
78
+ if err != nil {
79
+ return nil, err
80
+ }
81
+
82
+ switch pmes.GetType() {
83
+ case KeyType_RSA:
84
+ return UnmarshalRsaPrivateKey(pmes.GetData())
85
+ default:
86
+ return nil, ErrBadKeyType
87
+ }
88
+}
crypto/rsa.go
new
+94
@@ -0,0 +1,94 @@
1
+package crypto
2
+
3
+import (
4
+ "crypto"
5
+ "crypto/rand"
6
+ "crypto/rsa"
7
+ "crypto/sha256"
8
+ "crypto/x509"
9
+ "errors"
10
+
11
+ "code.google.com/p/goprotobuf/proto"
12
+)
13
+
14
+type RsaPrivateKey struct {
15
+ k *rsa.PrivateKey
16
+}
17
+
18
+type RsaPublicKey struct {
19
+ k *rsa.PublicKey
20
+}
21
+
22
+func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
23
+ hashed := sha256.Sum256(data)
24
+ err := rsa.VerifyPKCS1v15(pk.k, crypto.SHA256, hashed[:], sig)
25
+ if err != nil {
26
+ return false, err
27
+ }
28
+ return true, nil
29
+}
30
+
31
+func (pk *RsaPublicKey) Encrypt(message []byte) ([]byte, error) {
32
+ return rsa.EncryptPKCS1v15(rand.Reader, pk.k, message)
33
+}
34
+
35
+func (pk *RsaPublicKey) Bytes() ([]byte, error) {
36
+ b, err := x509.MarshalPKIXPublicKey(pk.k)
37
+ if err != nil {
38
+ return nil, err
39
+ }
40
+
41
+ pbmes := new(PBPublicKey)
42
+ typ := KeyType_RSA
43
+ pbmes.Type = &typ
44
+ pbmes.Data = b
45
+ return proto.Marshal(pbmes)
46
+}
47
+
48
+func (sk *RsaPrivateKey) GenSecret() []byte {
49
+ buf := make([]byte, 16)
50
+ rand.Read(buf)
51
+ return buf
52
+}
53
+
54
+func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
55
+ hashed := sha256.Sum256(message)
56
+ return rsa.SignPKCS1v15(rand.Reader, sk.k, crypto.SHA256, hashed[:])
57
+}
58
+
59
+func (sk *RsaPrivateKey) Decrypt(ciphertext []byte) ([]byte, error) {
60
+ return rsa.DecryptPKCS1v15(rand.Reader, sk.k, ciphertext)
61
+}
62
+
63
+func (sk *RsaPrivateKey) GetPublic() PubKey {
64
+ return &RsaPublicKey{&sk.k.PublicKey}
65
+}
66
+
67
+func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
68
+ b := x509.MarshalPKCS1PrivateKey(sk.k)
69
+ pbmes := new(PBPrivateKey)
70
+ typ := KeyType_RSA
71
+ pbmes.Type = &typ
72
+ pbmes.Data = b
73
+ return proto.Marshal(pbmes)
74
+}
75
+
76
+func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) {
77
+ sk, err := x509.ParsePKCS1PrivateKey(b)
78
+ if err != nil {
79
+ return nil, err
80
+ }
81
+ return &RsaPrivateKey{sk}, nil
82
+}
83
+
84
+func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) {
85
+ pub, err := x509.ParsePKIXPublicKey(b)
86
+ if err != nil {
87
+ return nil, err
88
+ }
89
+ pk, ok := pub.(*rsa.PublicKey)
90
+ if !ok {
91
+ return nil, errors.New("Not actually an rsa public key.")
92
+ }
93
+ return &RsaPublicKey{pk}, nil
94
+}
identify/identify.go
+9
-73
@@ -4,14 +4,10 @@ package identify
4
5
import (
6
"bytes"
7
- "crypto"
8
- "crypto/rand"
9
- "crypto/rsa"
10
- "crypto/x509"
7
"errors"
12
- "io/ioutil"
8
9
proto "code.google.com/p/goprotobuf/proto"
10
+ ci "github.com/jbenet/go-ipfs/crypto"
11
peer "github.com/jbenet/go-ipfs/peer"
12
u "github.com/jbenet/go-ipfs/util"
13
)
@@ -40,15 +36,14 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) error {
36
return verifyErr
37
}
38
43
- pubkey, err := x509.ParsePKIXPublicKey(pbresp.GetPubkey())
39
+ pubkey, err := ci.UnmarshalPublicKey(pbresp.GetPubkey())
40
if err != nil {
41
return err
42
}
43
44
// Challenge peer to ensure they own the given pubkey
49
- secret := make([]byte, 16)
50
- rand.Read(secret)
51
- encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey.(*rsa.PublicKey), secret)
45
+ secret := self.PrivKey.GenSecret()
46
+ encrypted, err := pubkey.Encrypt(secret)
47
if err != nil {
48
//... this is odd
49
return err
@@ -58,7 +53,7 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) error {
53
challenge := <-in
54
55
// Decrypt challenge and send plaintext to partner
61
- plain, err := rsa.DecryptPKCS1v15(rand.Reader, self.PrivKey.(*rsa.PrivateKey), challenge)
56
+ plain, err := self.PrivKey.Decrypt(challenge)
57
if err != nil {
58
return err
59
}
@@ -77,7 +72,7 @@ func Handshake(self, remote *peer.Peer, in, out chan []byte) error {
72
}
73
74
func buildHandshake(self *peer.Peer) ([]byte, error) {
80
- pkb, err := x509.MarshalPKIXPublicKey(self.PubKey)
75
+ pkb, err := self.PubKey.Bytes()
76
if err != nil {
77
return nil, err
78
}
@@ -107,73 +102,14 @@ func verifyID(id peer.ID, pubkey []byte) error {
102
return errors.New("ID did not match public key!")
103
}
104
110
-type KeyPair struct {
111
- Pub crypto.PublicKey
112
- Priv crypto.PrivateKey
113
-}
114
-
115
-func GenKeypair(bits int) (*KeyPair, error) {
116
- priv, err := rsa.GenerateKey(rand.Reader, bits)
117
- if err != nil {
118
- return nil, err
119
- }
120
-
121
- return &KeyPair{
122
- Priv: priv,
123
- Pub: &priv.PublicKey,
124
- }, nil
125
-}
126
-
127
-func LoadKeypair(dir string) (*KeyPair, error) {
128
- var kp KeyPair
129
- pk_b, err := ioutil.ReadFile(dir + "/priv.key")
130
- if err != nil {
131
- return nil, err
132
- }
133
-
134
- priv, err := x509.ParsePKCS1PrivateKey(pk_b)
135
- if err != nil {
136
- return nil, err
137
- }
138
-
139
- kp.Priv = priv
140
- kp.Pub = priv.PublicKey
141
-
142
- return &kp, nil
143
-}
144
-
145
-func (pk *KeyPair) ID() (peer.ID, error) {
146
- pub_b, err := x509.MarshalPKIXPublicKey(pk.Pub)
105
+func IdFromPubKey(pk ci.PubKey) (peer.ID, error) {
106
+ b, err := pk.Bytes()
107
if err != nil {
108
return nil, err
109
}
150
- hash, err := u.Hash(pub_b)
110
+ hash, err := u.Hash(b)
111
if err != nil {
112
return nil, err
113
}
114
return peer.ID(hash), nil
115
}
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:
169
- err := k.Validate()
170
- if err != nil {
171
- return err
172
- }
173
- pk_b := x509.MarshalPKCS1PrivateKey(k)
174
- err = ioutil.WriteFile(dir+"/priv.key", pk_b, 0600)
175
- return err
176
- default:
177
- return errors.New("invalid private key type.")
178
- }
179
-}
identify/identify_test.go
+9
-8
@@ -3,15 +3,16 @@ package identify
3
import (
4
"testing"
5
6
+ ci "github.com/jbenet/go-ipfs/crypto"
7
"github.com/jbenet/go-ipfs/peer"
8
)
9
10
func TestHandshake(t *testing.T) {
10
- kpa, err := GenKeypair(512)
11
+ ska, pka, err := ci.GenerateKeyPair(ci.RSA, 512)
12
if err != nil {
13
t.Fatal(err)
14
}
14
- kpb, err := GenKeypair(512)
15
+ skb, pkb, err := ci.GenerateKeyPair(ci.RSA, 512)
16
if err != nil {
17
t.Fatal(err)
18
}
@@ -19,24 +20,24 @@ func TestHandshake(t *testing.T) {
20
cha := make(chan []byte, 5)
21
chb := make(chan []byte, 5)
22
22
- ida, err := kpa.ID()
23
+ ida, err := IdFromPubKey(pka)
24
if err != nil {
25
t.Fatal(err)
26
}
27
pa := &peer.Peer{
28
ID: ida,
28
- PubKey: kpa.Pub,
29
- PrivKey: kpa.Priv,
29
+ PubKey: pka,
30
+ PrivKey: ska,
31
}
32
32
- idb, err := kpb.ID()
33
+ idb, err := IdFromPubKey(pkb)
34
if err != nil {
35
t.Fatal(err)
36
}
37
pb := &peer.Peer{
38
ID: idb,
38
- PubKey: kpb.Pub,
39
- PrivKey: kpb.Priv,
39
+ PubKey: pkb,
40
+ PrivKey: skb,
41
}
42
43
go func() {
peer/peer.go
+3
-3
@@ -1,11 +1,11 @@
1
package peer
2
3
import (
4
- "crypto"
4
"sync"
5
"time"
6
7
b58 "github.com/jbenet/go-base58"
8
+ ic "github.com/jbenet/go-ipfs/crypto"
9
u "github.com/jbenet/go-ipfs/util"
10
ma "github.com/jbenet/go-multiaddr"
11
mh "github.com/jbenet/go-multihash"
@@ -34,8 +34,8 @@ type Peer struct {
34
ID ID
35
Addresses []*ma.Multiaddr
36
37
- PubKey crypto.PublicKey
38
- PrivKey crypto.PrivateKey
37
+ PrivKey ic.PrivKey
38
+ PubKey ic.PubKey
39
40
latency time.Duration
41
latenLock sync.RWMutex
routing/dht/dht_test.go
+9
-8
@@ -4,6 +4,7 @@ import (
4
"testing"
5
6
ds "github.com/jbenet/datastore.go"
7
+ ci "github.com/jbenet/go-ipfs/crypto"
8
identify "github.com/jbenet/go-ipfs/identify"
9
peer "github.com/jbenet/go-ipfs/peer"
10
swarm "github.com/jbenet/go-ipfs/swarm"
@@ -28,13 +29,13 @@ func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT)
29
for i := 0; i < 4; i++ {
30
p := new(peer.Peer)
31
p.AddAddress(addrs[i])
31
- kp, err := identify.GenKeypair(256)
32
+ sk, pk, err := ci.GenerateKeyPair(ci.RSA, 256)
33
if err != nil {
34
panic(err)
35
}
35
- p.PubKey = kp.Pub
36
- p.PrivKey = kp.Priv
37
- id, err := kp.ID()
36
+ p.PubKey = pk
37
+ p.PrivKey = sk
38
+ id, err := identify.IdFromPubKey(pk)
39
if err != nil {
40
panic(err)
41
}
@@ -60,13 +61,13 @@ func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT)
61
func makePeer(addr *ma.Multiaddr) *peer.Peer {
62
p := new(peer.Peer)
63
p.AddAddress(addr)
63
- kp, err := identify.GenKeypair(256)
64
+ sk, pk, err := ci.GenerateKeyPair(ci.RSA, 256)
65
if err != nil {
66
panic(err)
67
}
67
- p.PrivKey = kp.Priv
68
- p.PubKey = kp.Pub
69
- id, err := kp.ID()
68
+ p.PrivKey = sk
69
+ p.PubKey = pk
70
+ id, err := identify.IdFromPubKey(pk)
71
if err != nil {
72
panic(err)
73
}