// ID returns the ID of a given Conn. func ID(c Conn) string { l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty()) r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty()) lh := u.Hash([]byte(l)) rh := u.Hash([]byte(r)) ch := u.XOR(lh, rh) return peer.ID(ch).Pretty() }
func TestRoutingResolve(t *testing.T) { dstore := dssync.MutexWrap(ds.NewMapDatastore()) serv := mockrouting.NewServer() id := testutil.RandIdentityOrFatal(t) d := serv.ClientWithDatastore(context.Background(), id, dstore) resolver := NewRoutingResolver(d, 0) publisher := NewRoutingPublisher(d, dstore) privk, pubk, err := testutil.RandTestKeyPair(512) if err != nil { t.Fatal(err) } h := path.FromString("/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN") err = publisher.Publish(context.Background(), privk, h) if err != nil { t.Fatal(err) } pubkb, err := pubk.Bytes() if err != nil { t.Fatal(err) } pkhash := u.Hash(pubkb) res, err := resolver.Resolve(context.Background(), key.Key(pkhash).B58String()) if err != nil { t.Fatal(err) } if res != h { t.Fatal("Got back incorrect value.") } }
// KeyHash hashes a key. func KeyHash(k Key) ([]byte, error) { kb, err := k.Bytes() if err != nil { return nil, err } return u.Hash(kb), nil }
// RandPeerID generates random "valid" peer IDs. it does not NEED to generate // keys because it is as if we lost the key right away. fine to read randomness // and hash it. to generate proper keys and corresponding PeerID, use: // sk, pk, _ := testutil.RandKeyPair() // id, _ := peer.IDFromPublicKey(pk) func RandPeerID() (peer.ID, error) { buf := make([]byte, 16) if _, err := io.ReadFull(u.NewTimeSeededRand(), buf); err != nil { return "", err } h := u.Hash(buf) return peer.ID(h), nil }
// IDFromPublicKey returns the Peer ID corresponding to pk func IDFromPublicKey(pk ic.PubKey) (ID, error) { b, err := pk.Bytes() if err != nil { return "", err } hash := u.Hash(b) return ID(hash), nil }
// NewBlockWithHash creates a new block when the hash of the data // is already known, this is used to save time in situations where // we are able to be confident that the data is correct func NewBlockWithHash(data []byte, h mh.Multihash) (*RawBlock, error) { if u.Debug { chk := u.Hash(data) if string(chk) != string(h) { return nil, errors.New("Data did not match given hash!") } } return &RawBlock{data: data, multihash: h}, nil }
// ValidatePublicKeyRecord implements ValidatorFunc and // verifies that the passed in record value is the PublicKey // that matches the passed in key. func ValidatePublicKeyRecord(k key.Key, val []byte) error { keyparts := bytes.Split([]byte(k), []byte("/")) if len(keyparts) < 3 { return errors.New("invalid key") } pkh := u.Hash(val) if !bytes.Equal(keyparts[2], pkh) { return errors.New("public key does not match storage key") } return nil }
// Encoded returns the encoded raw data version of a Node instance. // It may use a cached encoded version, unless the force flag is given. func (n *Node) Encoded(force bool) ([]byte, error) { sort.Stable(LinkSlice(n.Links)) // keep links sorted if n.encoded == nil || force { var err error n.encoded, err = n.Marshal() if err != nil { return nil, err } n.cached = u.Hash(n.encoded) } return n.encoded, nil }
func (ks *keyset) generate() error { var err error ks.sk, ks.pk, err = tu.RandTestKeyPair(512) if err != nil { return err } bpk, err := ks.pk.Bytes() if err != nil { return err } ks.hpk = string(u.Hash(bpk)) ks.hpkp = b58.Encode([]byte(ks.hpk)) return nil }
func TestBlocks(t *testing.T) { bstore := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) bs := New(bstore, offline.Exchange(bstore)) defer bs.Close() _, err := bs.GetBlock(context.Background(), key.Key("")) if err != ErrNotFound { t.Error("Empty String Key should error", err) } b := blocks.NewBlock([]byte("beep boop")) h := u.Hash([]byte("beep boop")) if !bytes.Equal(b.Multihash(), h) { t.Error("Block Multihash and data multihash not equal") } if b.Key() != key.Key(h) { t.Error("Block key and data multihash key not equal") } k, err := bs.AddBlock(b) if err != nil { t.Error("failed to add block to BlockService", err) return } if k != b.Key() { t.Error("returned key is not equal to block key", err) } ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() b2, err := bs.GetBlock(ctx, b.Key()) if err != nil { t.Error("failed to retrieve block from BlockService", err) return } if b.Key() != b2.Key() { t.Error("Block keys not equal.") } if !bytes.Equal(b.Data(), b2.Data()) { t.Error("Block data is not equal.") } }
// ValidatePublicKeyRecord implements ValidatorFunc and // verifies that the passed in record value is the PublicKey // that matches the passed in key. func ValidatePublicKeyRecord(k key.Key, val []byte) error { if len(k) < 5 { return errors.New("invalid public key record key") } prefix := string(k[:4]) if prefix != "/pk/" { return errors.New("key was not prefixed with /pk/") } keyhash := []byte(k[4:]) if _, err := mh.Cast(keyhash); err != nil { return fmt.Errorf("key did not contain valid multihash: %s", err) } pkh := u.Hash(val) if !bytes.Equal(keyhash, pkh) { return errors.New("public key does not match storage key") } return nil }
func (ks *keyset) load(hpkp, skBytesStr string) error { skBytes, err := base64.StdEncoding.DecodeString(skBytesStr) if err != nil { return err } ks.sk, err = ic.UnmarshalPrivateKey(skBytes) if err != nil { return err } ks.pk = ks.sk.GetPublic() bpk, err := ks.pk.Bytes() if err != nil { return err } ks.hpk = string(u.Hash(bpk)) ks.hpkp = b58.Encode([]byte(ks.hpk)) if ks.hpkp != hpkp { return fmt.Errorf("hpkp doesn't match key. %s", hpkp) } return nil }
// runBootstrap builds up list of peers by requesting random peer IDs func (dht *IpfsDHT) runBootstrap(ctx context.Context, cfg BootstrapConfig) error { bslog := func(msg string) { log.Debugf("DHT %s dhtRunBootstrap %s -- routing table size: %d", dht.self, msg, dht.routingTable.Size()) } bslog("start") defer bslog("end") defer log.EventBegin(ctx, "dhtRunBootstrap").Done() var merr u.MultiErr randomID := func() peer.ID { // 16 random bytes is not a valid peer id. it may be fine becuase // the dht will rehash to its own keyspace anyway. id := make([]byte, 16) rand.Read(id) id = u.Hash(id) return peer.ID(id) } // bootstrap sequentially, as results will compound ctx, cancel := context.WithTimeout(ctx, cfg.Timeout) defer cancel() runQuery := func(ctx context.Context, id peer.ID) { p, err := dht.FindPeer(ctx, id) if err == routing.ErrNotFound { // this isn't an error. this is precisely what we expect. } else if err != nil { merr = append(merr, err) } else { // woah, actually found a peer with that ID? this shouldn't happen normally // (as the ID we use is not a real ID). this is an odd error worth logging. err := fmt.Errorf("Bootstrap peer error: Actually FOUND peer. (%s, %s)", id, p) log.Warningf("%s", err) merr = append(merr, err) } } sequential := true if sequential { // these should be parallel normally. but can make them sequential for debugging. // note that the core/bootstrap context deadline should be extended too for that. for i := 0; i < cfg.Queries; i++ { id := randomID() log.Debugf("Bootstrapping query (%d/%d) to random ID: %s", i+1, cfg.Queries, id) runQuery(ctx, id) } } else { // note on parallelism here: the context is passed in to the queries, so they // **should** exit when it exceeds, making this function exit on ctx cancel. // normally, we should be selecting on ctx.Done() here too, but this gets // complicated to do with WaitGroup, and doesnt wait for the children to exit. var wg sync.WaitGroup for i := 0; i < cfg.Queries; i++ { wg.Add(1) go func() { defer wg.Done() id := randomID() log.Debugf("Bootstrapping query (%d/%d) to random ID: %s", i+1, cfg.Queries, id) runQuery(ctx, id) }() } wg.Wait() } if len(merr) > 0 { return merr } return nil }
// NewBlock creates a Block object from opaque data. It will hash the data. func NewBlock(data []byte) *Block { return &Block{Data: data, Multihash: u.Hash(data)} }
func newPeerTime(t time.Time) peer.ID { s := fmt.Sprintf("hmmm time: %v", t) h := u.Hash([]byte(s)) return peer.ID(h) }
// NewBlock creates a Block object from opaque data. It will hash the data. func NewBlock(data []byte) *RawBlock { return &RawBlock{data: data, multihash: u.Hash(data)} }
// runHandshake performs initial communication over insecure channel to share // keys, IDs, and initiate communication, assigning all necessary params. // requires the duplex channel to be a msgio.ReadWriter (for framed messaging) func (s *secureSession) runHandshake() error { ctx, cancel := context.WithTimeout(s.ctx, HandshakeTimeout) // remove defer cancel() // ============================================================================= // step 1. Propose -- propose cipher suite + send pubkeys + nonce // Generate and send Hello packet. // Hello = (rand, PublicKey, Supported) nonceOut := make([]byte, nonceSize) _, err := rand.Read(nonceOut) if err != nil { return err } defer log.EventBegin(ctx, "secureHandshake", s).Done() s.local.permanentPubKey = s.localKey.GetPublic() myPubKeyBytes, err := s.local.permanentPubKey.Bytes() if err != nil { return err } proposeOut := new(pb.Propose) proposeOut.Rand = nonceOut proposeOut.Pubkey = myPubKeyBytes proposeOut.Exchanges = &SupportedExchanges proposeOut.Ciphers = &SupportedCiphers proposeOut.Hashes = &SupportedHashes // log.Debugf("1.0 Propose: nonce:%s exchanges:%s ciphers:%s hashes:%s", // nonceOut, SupportedExchanges, SupportedCiphers, SupportedHashes) // Send Propose packet (respects ctx) proposeOutBytes, err := writeMsgCtx(ctx, s.insecureM, proposeOut) if err != nil { return err } // Receive + Parse their Propose packet and generate an Exchange packet. proposeIn := new(pb.Propose) proposeInBytes, err := readMsgCtx(ctx, s.insecureM, proposeIn) if err != nil { return err } // log.Debugf("1.0.1 Propose recv: nonce:%s exchanges:%s ciphers:%s hashes:%s", // proposeIn.GetRand(), proposeIn.GetExchanges(), proposeIn.GetCiphers(), proposeIn.GetHashes()) // ============================================================================= // step 1.1 Identify -- get identity from their key // get remote identity s.remote.permanentPubKey, err = ci.UnmarshalPublicKey(proposeIn.GetPubkey()) if err != nil { return err } // get peer id s.remotePeer, err = peer.IDFromPublicKey(s.remote.permanentPubKey) if err != nil { return err } log.Debugf("1.1 Identify: %s Remote Peer Identified as %s", s.localPeer, s.remotePeer) // ============================================================================= // step 1.2 Selection -- select/agree on best encryption parameters // to determine order, use cmp(H(remote_pubkey||local_rand), H(local_pubkey||remote_rand)). oh1 := u.Hash(append(proposeIn.GetPubkey(), nonceOut...)) oh2 := u.Hash(append(myPubKeyBytes, proposeIn.GetRand()...)) order := bytes.Compare(oh1, oh2) if order == 0 { return ErrEcho // talking to self (same socket. must be reuseport + dialing self) } s.local.curveT, err = selectBest(order, SupportedExchanges, proposeIn.GetExchanges()) if err != nil { return err } s.local.cipherT, err = selectBest(order, SupportedCiphers, proposeIn.GetCiphers()) if err != nil { return err } s.local.hashT, err = selectBest(order, SupportedHashes, proposeIn.GetHashes()) if err != nil { return err } // we use the same params for both directions (must choose same curve) // WARNING: if they dont SelectBest the same way, this won't work... s.remote.curveT = s.local.curveT s.remote.cipherT = s.local.cipherT s.remote.hashT = s.local.hashT // log.Debugf("1.2 selection: exchange:%s cipher:%s hash:%s", // s.local.curveT, s.local.cipherT, s.local.hashT) // ============================================================================= // step 2. Exchange -- exchange (signed) ephemeral keys. verify signatures. // Generate EphemeralPubKey var genSharedKey ci.GenSharedKey s.local.ephemeralPubKey, genSharedKey, err = ci.GenerateEKeyPair(s.local.curveT) // Gather corpus to sign. selectionOut := new(bytes.Buffer) selectionOut.Write(proposeOutBytes) selectionOut.Write(proposeInBytes) selectionOut.Write(s.local.ephemeralPubKey) selectionOutBytes := selectionOut.Bytes() // log.Debugf("2.0 exchange: %v", selectionOutBytes) exchangeOut := new(pb.Exchange) exchangeOut.Epubkey = s.local.ephemeralPubKey exchangeOut.Signature, err = s.localKey.Sign(selectionOutBytes) if err != nil { return err } // Send Propose packet (respects ctx) if _, err := writeMsgCtx(ctx, s.insecureM, exchangeOut); err != nil { return err } // Receive + Parse their Exchange packet. exchangeIn := new(pb.Exchange) if _, err := readMsgCtx(ctx, s.insecureM, exchangeIn); err != nil { return err } // ============================================================================= // step 2.1. Verify -- verify their exchange packet is good. // get their ephemeral pub key s.remote.ephemeralPubKey = exchangeIn.GetEpubkey() selectionIn := new(bytes.Buffer) selectionIn.Write(proposeInBytes) selectionIn.Write(proposeOutBytes) selectionIn.Write(s.remote.ephemeralPubKey) selectionInBytes := selectionIn.Bytes() // log.Debugf("2.0.1 exchange recv: %v", selectionInBytes) // u.POut("Remote Peer Identified as %s\n", s.remote) sigOK, err := s.remote.permanentPubKey.Verify(selectionInBytes, exchangeIn.GetSignature()) if err != nil { // log.Error("2.1 Verify: failed: %s", err) return err } if !sigOK { err := errors.New("Bad signature!") // log.Error("2.1 Verify: failed: %s", err) return err } // log.Debugf("2.1 Verify: signature verified.") // ============================================================================= // step 2.2. Keys -- generate keys for mac + encryption // OK! seems like we're good to go. s.sharedSecret, err = genSharedKey(exchangeIn.GetEpubkey()) if err != nil { return err } // generate two sets of keys (stretching) k1, k2 := ci.KeyStretcher(s.local.cipherT, s.local.hashT, s.sharedSecret) // use random nonces to decide order. switch { case order > 0: // just break case order < 0: k1, k2 = k2, k1 // swap default: // we should've bailed before this. but if not, bail here. return ErrEcho } s.local.keys = k1 s.remote.keys = k2 // log.Debug("2.2 keys:\n\tshared: %v\n\tk1: %v\n\tk2: %v", // s.sharedSecret, s.local.keys, s.remote.keys) // ============================================================================= // step 2.3. MAC + Cipher -- prepare MAC + cipher if err := s.local.makeMacAndCipher(); err != nil { return err } if err := s.remote.makeMacAndCipher(); err != nil { return err } // log.Debug("2.3 mac + cipher.") // ============================================================================= // step 3. Finish -- send expected message to verify encryption works (send local nonce) // setup ETM ReadWriter w := NewETMWriter(s.insecure, s.local.cipher, s.local.mac) r := NewETMReader(s.insecure, s.remote.cipher, s.remote.mac) s.secure = msgio.Combine(w, r).(msgio.ReadWriteCloser) // log.Debug("3.0 finish. sending: %v", proposeIn.GetRand()) // send their Nonce. if _, err := s.secure.Write(proposeIn.GetRand()); err != nil { return fmt.Errorf("Failed to write Finish nonce: %s", err) } // read our Nonce nonceOut2 := make([]byte, len(nonceOut)) if _, err := io.ReadFull(s.secure, nonceOut2); err != nil { return fmt.Errorf("Failed to read Finish nonce: %s", err) } // log.Debug("3.0 finish.\n\texpect: %v\n\tactual: %v", nonceOut, nonceOut2) if !bytes.Equal(nonceOut, nonceOut2) { return fmt.Errorf("Failed to read our encrypted nonce: %s != %s", nonceOut2, nonceOut) } // Whew! ok, that's all folks. return nil }
func TestMultisetRoundtrip(t *testing.T) { dstore := dssync.MutexWrap(datastore.NewMapDatastore()) bstore := blockstore.NewBlockstore(dstore) bserv := blockservice.New(bstore, offline.Exchange(bstore)) dag := merkledag.NewDAGService(bserv) fn := func(m map[key.Key]uint16) bool { // Convert invalid multihash from input to valid ones for k, v := range m { if _, err := mh.Cast([]byte(k)); err != nil { delete(m, k) m[key.Key(u.Hash([]byte(k)))] = v } } // Generate a smaller range for refcounts than full uint64, as // otherwise this just becomes overly cpu heavy, splitting it // out into too many items. That means we need to convert to // the right kind of map. As storeMultiset mutates the map as // part of its bookkeeping, this is actually good. refcounts := copyMap(m) ctx := context.Background() n, err := storeMultiset(ctx, dag, refcounts, ignoreKeys) if err != nil { t.Fatalf("storing multiset: %v", err) } // Check that the node n is in the DAG k, err := n.Key() if err != nil { t.Fatalf("Could not get key: %v", err) } _, err = dag.Get(ctx, k) if err != nil { t.Fatalf("Could not get node: %v", err) } root := &merkledag.Node{} const linkName = "dummylink" if err := root.AddNodeLink(linkName, n); err != nil { t.Fatalf("adding link to root node: %v", err) } roundtrip, err := loadMultiset(ctx, dag, root, linkName, ignoreKeys) if err != nil { t.Fatalf("loading multiset: %v", err) } orig := copyMap(m) success := true for k, want := range orig { if got, ok := roundtrip[k]; ok { if got != want { success = false t.Logf("refcount changed: %v -> %v for %q", want, got, k) } delete(orig, k) delete(roundtrip, k) } } for k, v := range orig { success = false t.Logf("refcount missing: %v for %q", v, k) } for k, v := range roundtrip { success = false t.Logf("refcount extra: %v for %q", v, k) } return success } if err := quick.Check(fn, nil); err != nil { t.Fatal(err) } }
// NewBlock creates a Block object from opaque data. It will hash the data. func NewBlock(data []byte) *BasicBlock { return &BasicBlock{data: data, multihash: u.Hash(data)} }