Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base of IPNS #19

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

// Identity tracks the configuration of the local node's identity.
type Identity struct {
PeerID string
Curve uint16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, why is the PeerID removed here? PeerIDs will survive beyond each launch (we don't generate them every time). Identities matter in BitSwap.

}

// Datastore tracks the configuration of the datastore.
Expand All @@ -24,7 +24,9 @@ type Config struct {

var defaultConfigFilePath = "~/.go-ipfs/config"
var defaultConfigFile = `{
"identity": {},
"identity": {
"curve": 224
},
"datastore": {
"type": "leveldb",
"path": "~/.go-ipfs/datastore"
Expand Down
6 changes: 6 additions & 0 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) {
return nil, fmt.Errorf("configuration required")
}

id, err := peer.NewIdentity(cfg.Identity)
if err != nil {
return nil, err
}

d, err := makeDatastore(cfg.Datastore)
if err != nil {
return nil, err
Expand All @@ -67,6 +72,7 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) {

n := &IpfsNode{
Config: cfg,
Identity: id,
PeerMap: &peer.Map{},
Datastore: d,
Blocks: bs,
Expand Down
46 changes: 46 additions & 0 deletions namesys/namesys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package namesys

import (
"errors"
proquint "github.com/Bren2010/proquint"
mh "github.com/jbenet/go-multihash"
"net"
"regexp"
"strings"
)

func Resolve(name string) (mh.Multihash, error) {
b58Exp := "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]*$"
pqExp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$"

isB58, err := regexp.MatchString(b58Exp, name)
if err != nil {
return nil, err
}

isPQ, err := regexp.MatchString(pqExp, name)
if err != nil {
return nil, err
}

if isB58 { // Is a base58 hash.
return mh.FromB58String(name)
} else if isPQ { // Is a Proquint identifier.
return mh.Multihash(proquint.Decode(name)), nil
} else { // Is a domain name. Hopefully.
txts, err := net.LookupTXT(name)
if err != nil {
return nil, err
}

for i := 0; i < len(txts); i++ {
var parts []string = strings.SplitN(txts[i], "=", 2)

if len(parts) == 2 && parts[0] == "ipfs" {
return mh.FromB58String(parts[1])
}
}

return nil, errors.New("Could not resolve IPNS.")
}
}
5 changes: 2 additions & 3 deletions path/path.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package path

import (
namesys "github.com/jbenet/go-ipfs/namesys"
"fmt"
merkledag "github.com/jbenet/go-ipfs/merkledag"
u "github.com/jbenet/go-ipfs/util"
mh "github.com/jbenet/go-multihash"
"path"
"strings"
)
Expand Down Expand Up @@ -33,8 +33,7 @@ func (s *Resolver) ResolvePath(fpath string) (*merkledag.Node, error) {
return nil, fmt.Errorf("ipfs path must contain at least one component")
}

// first element in the path is a b58 hash (for now)
h, err := mh.FromB58String(parts[0])
h, err := name.Resolve(parts[0])
if err != nil {
return nil, err
}
Expand Down
156 changes: 156 additions & 0 deletions peer/peer.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package peer

import (
config "github.com/jbenet/go-ipfs/config"
u "github.com/jbenet/go-ipfs/util"
ma "github.com/jbenet/go-multiaddr"
mh "github.com/jbenet/go-multihash"

"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"errors"
"math/big"
)

// ID is a byte slice representing the identity of a peer.
Expand All @@ -23,7 +31,12 @@ type Map map[u.Key]*Peer
// ID, and relevant Addresses.
type Peer struct {
ID ID
PubKey []byte
Addresses []*ma.Multiaddr

curve elliptic.Curve
hellman []byte
signing *ecdsa.PrivateKey
}

// Key returns the ID as a Key (string) for maps.
Expand Down Expand Up @@ -52,3 +65,146 @@ func (p *Peer) NetAddress(n string) *ma.Multiaddr {
}
return nil
}

// Generates a shared secret key between us and the given public key.
func (p *Peer) Secret(pubKey []byte) ([]byte, error) {
// Verify and unpack node's public key.
curveSize := p.curve.Params().BitSize

if len(pubKey) != (curveSize / 2) {
return nil, errors.New("Malformed public key.")
}

bound := (curveSize / 8)
x := big.NewInt(0)
y := big.NewInt(0)

x.SetBytes(pubKey[0:bound])
y.SetBytes(pubKey[bound : bound*2])

if !p.curve.IsOnCurve(x, y) {
return nil, errors.New("Invalid public key.")
}

// Generate shared secret.
secret, _ := p.curve.ScalarMult(x, y, p.hellman)

return secret.Bytes(), nil
}

// Signs a given piece of data.
func (p *Peer) Sign(data []byte) ([]byte, error) {
var out bytes.Buffer

hash := sha256.New()
hash.Write(data)

r, s, err := ecdsa.Sign(rand.Reader, p.signing, hash.Sum(nil))
if err != nil {
return nil, err
}

out.Write(r.Bytes())
out.Write(s.Bytes())

return out.Bytes(), nil
}

// Verifies a signature on a given piece of data.
func (p *Peer) Verify(pubKey, data, sig []byte) (bool, error) {
curveSize := p.curve.Params().BitSize

// Verify and unpack public key.
if len(pubKey) != (curveSize / 2) {
return false, errors.New("Malformed public key.")
}

bound1 := (curveSize / 8)
x := big.NewInt(0)
y := big.NewInt(0)

x.SetBytes(pubKey[bound1*2 : bound1*3])
y.SetBytes(pubKey[bound1*3:])

parsedPubKey := &ecdsa.PublicKey{p.curve, x, y}

// Verify and unpack signature.
if len(sig) != (curveSize / 4) {
return false, errors.New("Malformed signature.")
}

bound2 := (curveSize / 8)
r := big.NewInt(0)
s := big.NewInt(0)

r.SetBytes(sig[0:bound2])
s.SetBytes(sig[bound2:])

// Verify signature.
hash := sha256.New()
hash.Write(data)

ok := ecdsa.Verify(parsedPubKey, hash.Sum(nil), r, s)

return ok, nil
}

/**
* Generates a new, random peer identity.
*
* @return {Peer}
*/
func NewIdentity(cfg *config.Identity) (*Peer, error) {
// Select curve given in config.
var curve elliptic.Curve
var pubKey bytes.Buffer

switch cfg.Curve {
case 224:
curve = elliptic.P224()
case 256:
curve = elliptic.P256()
case 384:
curve = elliptic.P384()
case 521:
curve = elliptic.P521()
default:
return nil, errors.New("Bad curve name in config.")
}

// Generate a random ECDH keypair.
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, err
}

pubKey.Write(x.Bytes())
pubKey.Write(y.Bytes())

// Generate a random ECDSA keypair.
signingPriv, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, err
}

pubKey.Write(signingPriv.PublicKey.X.Bytes())
pubKey.Write(signingPriv.PublicKey.Y.Bytes())

// Generate peer ID
hash := sha1.New() // THIS NEEDS TO BE SHA256
hash.Write(pubKey.Bytes())

id, err := mh.EncodeName(hash.Sum(nil), "sha1")
if err != nil {
return nil, err
}

return &Peer{
id,
pubKey.Bytes(),
[]*ma.Multiaddr{},
curve,
priv,
signingPriv,
}, nil
}