Example #1
0
func TestStreamData(t *testing.T) {
	var serverPrivate, clientPrivate, serverPublic, clientPublic [32]byte

	randBytes(serverPrivate[:])
	randBytes(clientPrivate[:])
	curve25519.ScalarBaseMult(&serverPublic, &serverPrivate)
	curve25519.ScalarBaseMult(&clientPublic, &clientPrivate)

	x, y := NewBiDiPipe()
	client := NewClient(x, &clientPrivate, &clientPublic, &serverPublic)
	server := NewServer(y, &serverPrivate)

	clientComplete := make(chan bool)
	go func() {
		defer x.Close()
		err := client.Handshake()
		if err != nil {
			panic(err)
		}
		if _, err = client.Write(nil); err != nil {
			panic(err)
		}
		if _, err = client.Write([]byte("hello")); err != nil {
			panic(err)
		}
		if _, err = client.Write([]byte("world")); err != nil {
			panic(err)
		}
		if _, err = client.Write(make([]byte, 20*1024)); err != nil {
			panic(err)
		}
		close(clientComplete)
	}()

	serverComplete := make(chan bool)
	go func() {
		defer y.Close()
		err := server.Handshake()
		if err != nil {
			panic(err)
		}

		h := sha256.New()
		if _, err := io.Copy(h, server); err != nil {
			panic(err)
		}
		if h.Sum(nil)[0] != 0xec {
			panic("bad data received")
		}
		close(serverComplete)
	}()

	<-clientComplete
	<-serverComplete
}
Example #2
0
// FillKeyExchange sets elements of kx with key exchange information from the
// ratchet.
func (r *Ratchet) FillKeyExchange(kx *pond.KeyExchange) error {
	if r.kxPrivate0 == nil || r.kxPrivate1 == nil {
		return errors.New("ratchet: handshake already complete")
	}

	var public0, public1 [32]byte
	curve25519.ScalarBaseMult(&public0, r.kxPrivate0)
	curve25519.ScalarBaseMult(&public1, r.kxPrivate1)

	kx.Dh = public0[:]
	kx.Dh1 = public1[:]

	return nil
}
Example #3
0
func TestBox(t *testing.T) {
	var privateKey1, privateKey2 [32]byte
	for i := range privateKey1[:] {
		privateKey1[i] = 1
	}
	for i := range privateKey2[:] {
		privateKey2[i] = 2
	}

	var publicKey1 [32]byte
	curve25519.ScalarBaseMult(&publicKey1, &privateKey1)
	var message [64]byte
	for i := range message[:] {
		message[i] = 3
	}

	var nonce [24]byte
	for i := range nonce[:] {
		nonce[i] = 4
	}

	box := Seal(nil, message[:], &nonce, &publicKey1, &privateKey2)

	// expected was generated using the C implementation of NaCl.
	expected, _ := hex.DecodeString("78ea30b19d2341ebbdba54180f821eec265cf86312549bea8a37652a8bb94f07b78a73ed1708085e6ddd0e943bbdeb8755079a37eb31d86163ce241164a47629c0539f330b4914cd135b3855bc2a2dfc")

	if !bytes.Equal(box, expected) {
		t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
	}
}
Example #4
0
func UnmarshalKeyExchange(rand io.Reader, meetingPlace MeetingPlace, serialised []byte) (*KeyExchange, error) {
	var p panda_proto.KeyExchange
	if err := proto.Unmarshal(serialised, &p); err != nil {
		return nil, err
	}

	sharedSecret, ok := newSharedSecret(p.SharedSecret)
	if !ok {
		return nil, errors.New("panda: invalid shared secret in serialised key exchange")
	}

	kx := &KeyExchange{
		rand:         rand,
		meetingPlace: meetingPlace,
		status:       p.GetStatus(),
		sharedSecret: sharedSecret,
		serialised:   serialised,
		kxBytes:      p.KeyExchangeBytes,
		message1:     p.Message1,
		message2:     p.Message2,
	}

	copy(kx.key[:], p.Key)
	copy(kx.meeting1[:], p.Meeting1)
	copy(kx.meeting2[:], p.Meeting2)
	copy(kx.sharedKey[:], p.SharedKey)
	copy(kx.dhPrivate[:], p.DhPrivate)
	curve25519.ScalarBaseMult(&kx.dhPublic, &kx.dhPrivate)

	return kx, nil
}
Example #5
0
func (c *client) dialServer(server string, useRandomIdentity bool) (*transport.Conn, error) {
	identity := &c.identity
	identityPublic := &c.identityPublic
	if useRandomIdentity {
		var randomIdentity [32]byte
		c.randBytes(randomIdentity[:])

		var randomIdentityPublic [32]byte
		curve25519.ScalarBaseMult(&randomIdentityPublic, &randomIdentity)

		identity = &randomIdentity
		identityPublic = &randomIdentityPublic
	}

	serverIdentity, host, err := parseServer(server, c.testing)
	if err != nil {
		return nil, err
	}
	var tor proxy.Dialer
	if c.testing {
		tor = proxy.Direct
	} else {
		tor = c.torDialer()
	}
	rawConn, err := tor.Dial("tcp", host)
	if err != nil {
		return nil, err
	}
	conn := transport.NewClient(rawConn, identity, identityPublic, serverIdentity)
	if err := conn.Handshake(); err != nil {
		return nil, err
	}
	return conn, nil
}
Example #6
0
func NewTestServer(setup func(dir string)) *TestServer {
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)})
	if err != nil {
		panic(err)
	}

	dir, err := ioutil.TempDir("", "servertest")
	if err != nil {
		panic(err)
	}

	if setup != nil {
		setup(dir)
	}

	testServer := &TestServer{
		listener: listener,
		addr:     listener.Addr().(*net.TCPAddr),
		dir:      dir,
		server:   NewServer(dir, true),
	}
	io.ReadFull(rand.Reader, testServer.identity[:])
	curve25519.ScalarBaseMult(&testServer.identityPublic, &testServer.identity)

	go testServer.Loop()
	return testServer
}
Example #7
0
// GenerateKey returns an appropriate private and public key pair
// for securing messages.
func GenerateKey() (priv *[PrivateKeySize]byte, pub *[PublicKeySize]byte, ok bool) {
	var priv1 [32]byte
	var priv2 [32]byte
	var pub1 [32]byte
	var pub2 [32]byte

	_, err := io.ReadFull(PRNG, priv1[:])
	if err != nil {
		return
	}

	_, err = io.ReadFull(PRNG, priv2[:])
	if err != nil {
		return
	}

	h := sha3.NewKeccak384()
	h.Write(priv1[:])
	digest := h.Sum(nil)
	copy(priv1[:], digest)
	priv1[0] &= 248
	priv1[31] &= 127
	priv1[31] |= 64

	h.Reset()
	h.Write(priv2[:])
	digest = h.Sum(nil)
	copy(priv2[:], digest)
	priv2[0] &= 248
	priv2[31] &= 127
	priv2[31] |= 64

	curve25519.ScalarBaseMult(&pub1, &priv1)
	curve25519.ScalarBaseMult(&pub2, &priv2)
	priv = new([PrivateKeySize]byte)
	copy(priv[:32], priv1[:])
	copy(priv[32:], priv2[:])

	pub = new([PublicKeySize]byte)
	copy(pub[:32], pub1[:])
	copy(pub[32:], pub2[:])
	secretbox.Zero(priv1[:])
	secretbox.Zero(priv2[:])

	ok = true
	return
}
Example #8
0
// Pubkey returns the associated public key for the supplied private key.
func (k *Private) Pubkey() *Public {
	var pub [32]byte
	priv := [32]byte(*k)

	// Performs ScalarBaseMult on the supplied private key, returning the public key
	curve25519.ScalarBaseMult(&pub, &priv)
	public := Public(pub)
	return &public
}
Example #9
0
File: network.go Project: nico/pond
func (c *client) doCreateAccount() error {
	_, _, err := parseServer(c.server, c.dev)
	if err != nil {
		return err
	}

	if !c.dev {
		// Check that Tor is running.
		testConn, err := net.Dial("tcp", c.torAddress)
		if err != nil {
			return errors.New("Failed to connect to local Tor: " + err.Error())
		}
		testConn.Close()
	}

	c.ui.Actions() <- SetText{name: "status", text: "Generating keys..."}
	c.ui.Signal()

	c.randBytes(c.identity[:])
	curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

	c.ui.Actions() <- SetText{name: "status", text: "Connecting..."}
	c.ui.Signal()

	conn, err := c.dialServer(c.server, false)
	if err != nil {
		return err
	}
	defer conn.Close()

	c.ui.Actions() <- SetText{name: "status", text: "Requesting new account..."}
	c.ui.Signal()

	c.generation = uint32(c.randId())

	request := new(pond.Request)
	request.NewAccount = &pond.NewAccount{
		Generation: proto.Uint32(c.generation),
		Group:      c.groupPriv.Group.Marshal(),
	}
	if err := conn.WriteProto(request); err != nil {
		return err
	}

	reply := new(pond.Reply)
	if err := conn.ReadProto(reply); err != nil {
		return err
	}
	if err := replyToError(reply); err != nil {
		return err
	}

	c.ui.Actions() <- SetText{name: "status", text: "Done"}
	c.ui.Signal()

	return nil
}
Example #10
0
// GetKeyExchangeMaterial returns key exchange information from the
// ratchet.
func (r *Ratchet) GetKeyExchangeMaterial() (kx *KeyExchange, err error) {
	if r.kxPrivate0 == nil || r.kxPrivate1 == nil {
		return new(KeyExchange), errors.New("ratchet: handshake already complete")
	}

	var public0, public1, myIdentity [32]byte
	curve25519.ScalarBaseMult(&public0, r.kxPrivate0)
	curve25519.ScalarBaseMult(&public1, r.kxPrivate1)
	curve25519.ScalarBaseMult(&myIdentity, &r.myIdentityPrivate)

	kx = &KeyExchange{
		IdentityPublic: toSlice(myIdentity),
		Dh:             toSlice(public0),
		Dh1:            toSlice(public1),
	}

	return
}
Example #11
0
func TestHandshake(t *testing.T) {
	var serverPrivate, clientPrivate, serverPublic, clientPublic [32]byte

	randBytes(serverPrivate[:])
	randBytes(clientPrivate[:])
	curve25519.ScalarBaseMult(&serverPublic, &serverPrivate)
	curve25519.ScalarBaseMult(&clientPublic, &clientPrivate)

	clientError, serverError := runHandshake(&clientPrivate, &clientPublic, &serverPrivate, &serverPublic)
	if clientError != nil || serverError != nil {
		t.Fatalf("handshake failed: client:'%s' server:'%s'", clientError, serverError)
	}

	serverPublic[0] ^= 0x40
	clientError, serverError = runHandshake(&clientPrivate, &clientPublic, &serverPrivate, &serverPublic)
	if clientError == nil && serverError == nil {
		t.Fatal("bad handshake succeeded")
	}
}
Example #12
0
func pairedRatchet() (a, b *Ratchet) {
	var privA, pubA, privB, pubB [32]byte
	io.ReadFull(rand.Reader, privA[:])
	io.ReadFull(rand.Reader, privB[:])
	curve25519.ScalarBaseMult(&pubA, &privA)
	curve25519.ScalarBaseMult(&pubB, &privB)

	// These are the "Ed25519" public keys for the two parties. Of course,
	// they're not actually valid Ed25519 keys but that doesn't matter
	// here.
	var aSigningPublic, bSigningPublic [32]byte
	io.ReadFull(rand.Reader, aSigningPublic[:])
	io.ReadFull(rand.Reader, bSigningPublic[:])

	a, b = New(rand.Reader), New(rand.Reader)
	a.Now = nowFunc
	b.Now = nowFunc
	a.MyIdentityPrivate = &privA
	b.MyIdentityPrivate = &privB
	a.TheirIdentityPublic = &pubB
	b.TheirIdentityPublic = &pubA
	a.MySigningPublic = &aSigningPublic
	b.MySigningPublic = &bSigningPublic
	a.TheirSigningPublic = &bSigningPublic
	b.TheirSigningPublic = &aSigningPublic

	kxA, kxB := new(pond.KeyExchange), new(pond.KeyExchange)
	if err := a.FillKeyExchange(kxA); err != nil {
		panic(err)
	}
	if err := b.FillKeyExchange(kxB); err != nil {
		panic(err)
	}
	if err := a.CompleteKeyExchange(kxB, true); err != nil {
		panic(err)
	}
	if err := b.CompleteKeyExchange(kxA, true); err != nil {
		panic(err)
	}

	return
}
Example #13
0
func (e *curve25519ECDH) GenerateKey(rand io.Reader) (crypto.PrivateKey, crypto.PublicKey, error) {
	var pub, priv [32]byte
	var err error

	_, err = io.ReadFull(rand, priv[:])
	if err != nil {
		return nil, nil, err
	}

	curve25519.ScalarBaseMult(&pub, &priv)
	return &priv, &pub, nil
}
Example #14
0
// GenerateKey generates a new public/private key pair suitable for use with
// Seal and Open.
func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error) {
	publicKey = new([32]byte)
	privateKey = new([32]byte)
	_, err = io.ReadFull(rand, privateKey[:])
	if err != nil {
		publicKey = nil
		privateKey = nil
		return
	}

	curve25519.ScalarBaseMult(publicKey, privateKey)
	return
}
Example #15
0
func (noise255) GenerateKey(random io.Reader) (Key, error) {
	var pubKey, privKey [32]byte
	if random == nil {
		random = rand.Reader
	}
	if _, err := io.ReadFull(random, privKey[:]); err != nil {
		return Key{}, err
	}
	privKey[0] &= 248
	privKey[31] &= 127
	privKey[31] |= 64
	curve25519.ScalarBaseMult(&pubKey, &privKey)
	return Key{Private: privKey[:], Public: pubKey[:]}, nil
}
Example #16
0
// Encrypt acts like append() but appends an encrypted version of msg to out.
func (r *Ratchet) Encrypt(out, msg []byte) []byte {
	if r.ratchet {
		r.randBytes(r.sendRatchetPrivate[:])
		copy(r.sendHeaderKey[:], r.nextSendHeaderKey[:])

		var sharedKey, keyMaterial [32]byte
		curve25519.ScalarMult(&sharedKey, &r.sendRatchetPrivate, &r.recvRatchetPublic)
		sha := sha256.New()
		sha.Write(rootKeyUpdateLabel)
		sha.Write(r.rootKey[:])
		sha.Write(sharedKey[:])

		if r.v2 {
			sha.Sum(keyMaterial[:0])
			h := hmac.New(sha256.New, keyMaterial[:])
			deriveKey(&r.rootKey, rootKeyLabel, h)
			deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h)
			deriveKey(&r.sendChainKey, chainKeyLabel, h)
		} else {
			sha.Sum(r.rootKey[:0])
			h := hmac.New(sha256.New, r.rootKey[:])
			deriveKey(&r.nextSendHeaderKey, sendHeaderKeyLabel, h)
			deriveKey(&r.sendChainKey, chainKeyLabel, h)
		}
		r.prevSendCount, r.sendCount = r.sendCount, 0
		r.ratchet = false
	}

	h := hmac.New(sha256.New, r.sendChainKey[:])
	var messageKey [32]byte
	deriveKey(&messageKey, messageKeyLabel, h)
	deriveKey(&r.sendChainKey, chainKeyStepLabel, h)

	var sendRatchetPublic [32]byte
	curve25519.ScalarBaseMult(&sendRatchetPublic, &r.sendRatchetPrivate)
	var header [headerSize]byte
	var headerNonce, messageNonce [24]byte
	r.randBytes(headerNonce[:])
	r.randBytes(messageNonce[:])

	binary.LittleEndian.PutUint32(header[0:4], r.sendCount)
	binary.LittleEndian.PutUint32(header[4:8], r.prevSendCount)
	copy(header[8:], sendRatchetPublic[:])
	copy(header[nonceInHeaderOffset:], messageNonce[:])
	out = append(out, headerNonce[:]...)
	out = secretbox.Seal(out, header[:], &headerNonce, &r.sendHeaderKey)
	r.sendCount++
	return secretbox.Seal(out, msg, &messageNonce, &messageKey)
}
Example #17
0
func (c *client) sendAck(msg *InboxMessage) {
	// First, see if we can merge this ack with a message to the same
	// contact that is pending transmission.
	c.queueMutex.Lock()
	for _, queuedMsg := range c.queue {
		if queuedMsg.sending {
			continue
		}
		if msg.from == queuedMsg.to && !queuedMsg.revocation {
			proto := queuedMsg.message
			proto.AlsoAck = append(proto.AlsoAck, msg.message.GetId())
			if !tooLarge(queuedMsg) {
				c.queueMutex.Unlock()
				c.log.Printf("ACK merged with queued message.")
				// All done.
				return
			}

			proto.AlsoAck = proto.AlsoAck[:len(proto.AlsoAck)-1]
			if len(proto.AlsoAck) == 0 {
				proto.AlsoAck = nil
			}
		}
	}
	c.queueMutex.Unlock()

	to := c.contacts[msg.from]

	var myNextDH []byte
	if to.ratchet == nil {
		var nextDHPub [32]byte
		curve25519.ScalarBaseMult(&nextDHPub, &to.currentDHPrivate)
		myNextDH = nextDHPub[:]
	}

	id := c.randId()
	err := c.send(to, &pond.Message{
		Id:               proto.Uint64(id),
		Time:             proto.Int64(time.Now().Unix()),
		Body:             make([]byte, 0),
		BodyEncoding:     pond.Message_RAW.Enum(),
		MyNextDh:         myNextDH,
		InReplyTo:        msg.message.Id,
		SupportedVersion: proto.Int32(protoVersion),
	})
	if err != nil {
		c.log.Errorf("Error sending message: %s", err)
	}
}
Example #18
0
func TestCurve25519Conversion(t *testing.T) {
	public, private, _ := ed25519.GenerateKey(rand.Reader)

	var curve25519Public, curve25519Public2, curve25519Private [32]byte
	PrivateKeyToCurve25519(&curve25519Private, private)
	curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private)

	if !PublicKeyToCurve25519(&curve25519Public2, public) {
		t.Fatalf("PublicKeyToCurve25519 failed")
	}

	if !bytes.Equal(curve25519Public[:], curve25519Public2[:]) {
		t.Errorf("Values didn't match: curve25519 produced %x, conversion produced %x", curve25519Public[:], curve25519Public2[:])
	}
}
Example #19
0
func TestHandshake(t *testing.T) {
	var serverPrivate, clientPrivate, serverPublic, clientPublic [32]byte

	if _, err := io.ReadFull(rand.Reader, serverPrivate[:]); err != nil {
		t.Fatalf("reading from rand: %s", err)
	}
	if _, err := io.ReadFull(rand.Reader, clientPrivate[:]); err != nil {
		t.Fatalf("reading from rand: %s", err)
	}

	curve25519.ScalarBaseMult(&serverPublic, &serverPrivate)
	curve25519.ScalarBaseMult(&clientPublic, &clientPrivate)

	clientError, serverError := runHandshake(&clientPrivate, &clientPublic, &serverPrivate, &serverPublic)
	if clientError != nil || serverError != nil {
		t.Fatalf("handshake failed: client:'%s' server:'%s'", clientError, serverError)
	}

	serverPublic[0] ^= 0x40
	clientError, serverError = runHandshake(&clientPrivate, &clientPublic, &serverPrivate, &serverPublic)
	if clientError == nil && serverError == nil {
		t.Fatal("bad handshake succeeded")
	}
}
Example #20
0
File: network.go Project: nico/pond
func (c *client) sendAck(msg *InboxMessage) {
	to := c.contacts[msg.from]

	var nextDHPub [32]byte
	curve25519.ScalarBaseMult(&nextDHPub, &to.currentDHPrivate)

	id := c.randId()
	err := c.send(to, &pond.Message{
		Id:               proto.Uint64(id),
		Time:             proto.Int64(time.Now().Unix()),
		Body:             make([]byte, 0),
		BodyEncoding:     pond.Message_RAW.Enum(),
		MyNextDh:         nextDHPub[:],
		InReplyTo:        msg.message.Id,
		SupportedVersion: proto.Int32(protoVersion),
	})
	if err != nil {
		c.log.Errorf("Error sending message: %s", err)
	}
}
Example #21
0
func TestElligator(t *testing.T) {
	var publicKey, publicKey2, publicKey3, representative, privateKey [32]byte

	for i := 0; i < 1000; i++ {
		rand.Reader.Read(privateKey[:])

		if !ScalarBaseMult(&publicKey, &representative, &privateKey) {
			continue
		}
		RepresentativeToPublicKey(&publicKey2, &representative)
		if !bytes.Equal(publicKey[:], publicKey2[:]) {
			t.Fatal("The resulting public key doesn't match the initial one.")
		}

		curve25519.ScalarBaseMult(&publicKey3, &privateKey)
		if !bytes.Equal(publicKey[:], publicKey3[:]) {
			t.Fatal("The public key doesn't match the value that curve25519 produced.")
		}
	}
}
Example #22
0
func NewKeyExchange(rand io.Reader, meetingPlace MeetingPlace, sharedSecret *SharedSecret, kxBytes []byte) (*KeyExchange, error) {
	if 24 /* nonce */ +4 /* length */ +len(kxBytes)+secretbox.Overhead > meetingPlace.Padding() {
		return nil, errors.New("panda: key exchange too large for meeting place")
	}

	kx := &KeyExchange{
		Log:          func(format string, args ...interface{}) {},
		rand:         rand,
		meetingPlace: meetingPlace,
		status:       panda_proto.KeyExchange_INIT,
		sharedSecret: sharedSecret,
		kxBytes:      kxBytes,
	}

	if _, err := io.ReadFull(kx.rand, kx.dhPrivate[:]); err != nil {
		return nil, err
	}
	curve25519.ScalarBaseMult(&kx.dhPublic, &kx.dhPrivate)
	kx.updateSerialised()

	return kx, nil
}
Example #23
0
File: network.go Project: nico/pond
func (c *client) dialServer(server string, useRandomIdentity bool) (*transport.Conn, error) {
	identity := &c.identity
	identityPublic := &c.identityPublic
	if useRandomIdentity {
		var randomIdentity [32]byte
		c.randBytes(randomIdentity[:])

		var randomIdentityPublic [32]byte
		curve25519.ScalarBaseMult(&randomIdentityPublic, &randomIdentity)

		identity = &randomIdentity
		identityPublic = &randomIdentityPublic
	}

	serverIdentity, host, err := parseServer(server, c.dev)
	if err != nil {
		return nil, err
	}
	var tor proxy.Dialer
	if c.dev {
		tor = proxy.Direct
	} else {
		tor = c.torDialer()
	}
	rawConn, err := tor.Dial("tcp", host)
	if err != nil {
		return nil, err
	}
	// Sometimes Tor holds the connection open but we never receive
	// anything so we add a 60 second deadline.
	rawConn.SetDeadline(time.Now().Add(60 * time.Second))
	conn := transport.NewClient(rawConn, identity, identityPublic, serverIdentity)
	if err := conn.Handshake(); err != nil {
		return nil, err
	}
	return conn, nil
}
Example #24
0
File: client.go Project: nico/pond
func (c *client) newKeyExchange(contact *Contact) {
	var err error
	c.randBytes(contact.lastDHPrivate[:])
	c.randBytes(contact.currentDHPrivate[:])

	var pub [32]byte
	curve25519.ScalarBaseMult(&pub, &contact.lastDHPrivate)
	if contact.groupKey, err = c.groupPriv.NewMember(c.rand); err != nil {
		panic(err)
	}

	kx := &pond.KeyExchange{
		PublicKey:      c.pub[:],
		IdentityPublic: c.identityPublic[:],
		Server:         proto.String(c.server),
		Dh:             pub[:],
		Group:          contact.groupKey.Group.Marshal(),
		GroupKey:       contact.groupKey.Marshal(),
		Generation:     proto.Uint32(c.generation),
	}

	kxBytes, err := proto.Marshal(kx)
	if err != nil {
		panic(err)
	}

	sig := ed25519.Sign(&c.priv, kxBytes)

	kxs := &pond.SignedKeyExchange{
		Signed:    kxBytes,
		Signature: sig[:],
	}

	if contact.kxsBytes, err = proto.Marshal(kxs); err != nil {
		panic(err)
	}
}
Example #25
0
func (c *Conn) Handshake() error {
	var ephemeralPrivate, ephemeralPublic, ephemeralShared [32]byte
	if _, err := io.ReadFull(rand.Reader, ephemeralPrivate[:]); err != nil {
		return err
	}
	curve25519.ScalarBaseMult(&ephemeralPublic, &ephemeralPrivate)

	if _, err := c.write(ephemeralPublic[:]); err != nil {
		return err
	}

	var theirEphemeralPublic [32]byte
	if n, err := c.read(theirEphemeralPublic[:]); err != nil || n != len(theirEphemeralPublic) {
		if err == nil {
			err = shortMessageError
		}
		return err
	}

	handshakeHash := sha256.New()
	if c.isServer {
		handshakeHash.Write(theirEphemeralPublic[:])
		handshakeHash.Write(ephemeralPublic[:])
	} else {
		handshakeHash.Write(ephemeralPublic[:])
		handshakeHash.Write(theirEphemeralPublic[:])
	}

	curve25519.ScalarMult(&ephemeralShared, &ephemeralPrivate, &theirEphemeralPublic)
	c.setupKeys(&ephemeralShared)

	if c.isServer {
		return c.handshakeServer(handshakeHash, &theirEphemeralPublic)
	}
	return c.handshakeClient(handshakeHash, &ephemeralPrivate)
}
Example #26
0
func (c *client) unmarshal(state *disk.State) error {
	c.server = *state.Server

	if len(state.Identity) != len(c.identity) {
		return errors.New("client: identity is wrong length in State")
	}
	copy(c.identity[:], state.Identity)
	curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

	group, ok := new(bbssig.Group).Unmarshal(state.Group)
	if !ok {
		return errors.New("client: failed to unmarshal group")
	}
	c.groupPriv, ok = new(bbssig.PrivateKey).Unmarshal(group, state.GroupPrivate)
	if !ok {
		return errors.New("client: failed to unmarshal group private key")
	}

	if len(state.Private) != len(c.priv) {
		return errors.New("client: failed to unmarshal private key")
	}
	copy(c.priv[:], state.Private)
	if len(state.Public) != len(c.pub) {
		return errors.New("client: failed to unmarshal public key")
	}
	copy(c.pub[:], state.Public)
	c.generation = *state.Generation

	if state.LastErasureStorageTime != nil {
		c.lastErasureStorageTime = time.Unix(*state.LastErasureStorageTime, 0)
	}

	for _, prevGroupPriv := range state.PreviousGroupPrivateKeys {
		group, ok := new(bbssig.Group).Unmarshal(prevGroupPriv.Group)
		if !ok {
			return errors.New("client: failed to unmarshal previous group")
		}
		priv, ok := new(bbssig.PrivateKey).Unmarshal(group, prevGroupPriv.GroupPrivate)
		if !ok {
			return errors.New("client: failed to unmarshal previous group private key")
		}
		c.prevGroupPrivs = append(c.prevGroupPrivs, previousGroupPrivateKey{
			priv:    priv,
			expired: time.Unix(*prevGroupPriv.Expired, 0),
		})
	}

	for _, cont := range state.Contacts {
		contact := &Contact{
			id:               *cont.Id,
			name:             *cont.Name,
			kxsBytes:         cont.KeyExchangeBytes,
			pandaKeyExchange: cont.PandaKeyExchange,
			pandaResult:      cont.GetPandaError(),
			revokedUs:        cont.GetRevokedUs(),
		}
		c.registerId(contact.id)
		c.contacts[contact.id] = contact
		if contact.groupKey, ok = new(bbssig.MemberKey).Unmarshal(c.groupPriv.Group, cont.GroupKey); !ok {
			return errors.New("client: failed to unmarshal group member key")
		}
		copy(contact.lastDHPrivate[:], cont.LastPrivate)
		copy(contact.currentDHPrivate[:], cont.CurrentPrivate)

		if cont.Ratchet != nil {
			contact.ratchet = c.newRatchet(contact)
			if err := contact.ratchet.Unmarshal(cont.Ratchet); err != nil {
				return err
			}
		}

		if cont.IsPending != nil && *cont.IsPending {
			contact.isPending = true
			continue
		}

		theirGroup, ok := new(bbssig.Group).Unmarshal(cont.TheirGroup)
		if !ok {
			return errors.New("client: failed to unmarshal their group")
		}
		if contact.myGroupKey, ok = new(bbssig.MemberKey).Unmarshal(theirGroup, cont.MyGroupKey); !ok {
			return errors.New("client: failed to unmarshal my group key")
		}

		if cont.TheirServer == nil {
			return errors.New("client: contact missing server")
		}
		contact.theirServer = *cont.TheirServer

		if len(cont.TheirPub) != len(contact.theirPub) {
			return errors.New("client: contact missing public key")
		}
		copy(contact.theirPub[:], cont.TheirPub)

		if len(cont.TheirIdentityPublic) != len(contact.theirIdentityPublic) {
			return errors.New("client: contact missing identity public key")
		}
		copy(contact.theirIdentityPublic[:], cont.TheirIdentityPublic)

		copy(contact.theirLastDHPublic[:], cont.TheirLastPublic)
		copy(contact.theirCurrentDHPublic[:], cont.TheirCurrentPublic)

		for _, prevTag := range cont.PreviousTags {
			contact.previousTags = append(contact.previousTags, previousTag{
				tag:     prevTag.Tag,
				expired: time.Unix(*prevTag.Expired, 0),
			})
		}

		// For now we'll have to do this conditionally until everyone
		// has updated local state.
		if cont.Generation != nil {
			contact.generation = *cont.Generation
		}
		if cont.SupportedVersion != nil {
			contact.supportedVersion = *cont.SupportedVersion
		}
	}

	now := c.Now()
	for _, m := range state.Inbox {
		msg := &InboxMessage{
			id:           *m.Id,
			from:         *m.From,
			receivedTime: time.Unix(*m.ReceivedTime, 0),
			acked:        *m.Acked,
			read:         *m.Read,
			sealed:       m.Sealed,
			retained:     m.GetRetained(),
			exposureTime: now,
		}
		c.registerId(msg.id)
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in inbox: " + err.Error())
			}
		}

		c.inbox = append(c.inbox, msg)
	}

	for _, m := range state.Outbox {
		msg := &queuedMessage{
			id:      *m.Id,
			to:      *m.To,
			server:  *m.Server,
			created: time.Unix(*m.Created, 0),
		}
		c.registerId(msg.id)
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in outbox: " + err.Error())
			}
		}
		if m.Sent != nil {
			msg.sent = time.Unix(*m.Sent, 0)
		}
		if m.Acked != nil {
			msg.acked = time.Unix(*m.Acked, 0)
		}
		if len(m.Request) != 0 {
			msg.request = new(pond.Request)
			if err := proto.Unmarshal(m.Request, msg.request); err != nil {
				return errors.New("client: corrupt request in outbox: " + err.Error())
			}
		}
		msg.revocation = m.GetRevocation()
		if msg.revocation && len(msg.server) == 0 {
			// There was a bug in some versions where revoking a
			// pending contact would result in a revocation message
			// with an empty server.
			msg.server = c.server
		}

		c.outbox = append(c.outbox, msg)

		if msg.sent.IsZero() && (msg.to == 0 || !c.contacts[msg.to].revokedUs) {
			// This message hasn't been sent yet.
			c.enqueue(msg)
		}
	}

	for _, m := range state.Drafts {
		draft := &Draft{
			id:          *m.Id,
			body:        *m.Body,
			attachments: m.Attachments,
			detachments: m.Detachments,
			created:     time.Unix(*m.Created, 0),
		}
		c.registerId(draft.id)
		if m.To != nil {
			draft.to = *m.To
		}
		if m.InReplyTo != nil {
			draft.inReplyTo = *m.InReplyTo
		}

		c.drafts[draft.id] = draft
	}

	return nil
}
Example #27
0
func main() {
	flag.Parse()

	if len(*makeAnnounce) > 0 {
		msgBytes, err := ioutil.ReadFile(*makeAnnounce)
		if err != nil {
			panic(err)
		}
		announce := &pond.Message{
			Id:           proto.Uint64(0),
			Time:         proto.Int64(time.Now().Unix()),
			Body:         msgBytes,
			MyNextDh:     []byte{},
			BodyEncoding: pond.Message_RAW.Enum(),
		}
		announceBytes, err := proto.Marshal(announce)
		if err != nil {
			panic(err)
		}
		os.Stdout.Write(announceBytes)
		return
	}

	if len(*baseDirectory) == 0 {
		log.Fatalf("Must give --base-directory")
		return
	}
	configPath := filepath.Join(*baseDirectory, configFilename)

	var identity [32]byte
	if *initFlag {
		if err := os.MkdirAll(*baseDirectory, 0700); err != nil {
			log.Fatalf("Failed to create base directory: %s", err)
			return
		}

		if _, err := io.ReadFull(rand.Reader, identity[:]); err != nil {
			log.Fatalf("Failed to read random bytes: %s", err)
			return
		}

		if err := ioutil.WriteFile(filepath.Join(*baseDirectory, identityFilename), identity[:], 0600); err != nil {
			log.Fatalf("Failed to write identity file: %s", err)
			return
		}

		defaultConfig := &protos.Config{
			Port: proto.Uint32(uint32(*port)),
		}

		configFile, err := os.OpenFile(configPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
		if err != nil {
			log.Fatalf("Failed to create config file: %s", err)
		}
		proto.MarshalText(configFile, defaultConfig)
		configFile.Close()
	}

	identityBytes, err := ioutil.ReadFile(filepath.Join(*baseDirectory, identityFilename))
	if err != nil {
		log.Print("Use --init to setup a new base directory")
		log.Fatalf("Failed to read identity file: %s", err)
		return
	}
	if len(identityBytes) != 32 {
		log.Fatalf("Identity file is not 32 bytes long")
		return
	}
	copy(identity[:], identityBytes)

	config := new(protos.Config)
	configBytes, err := ioutil.ReadFile(configPath)
	if err != nil {
		log.Fatalf("No config file found")
	}

	if err := proto.UnmarshalText(string(configBytes), config); err != nil {
		log.Fatalf("Failed to parse config: %s", err)
	}

	ip := net.IPv4(127, 0, 0, 1) // IPv4 loopback interface

	if config.Address != nil {
		if ip = net.ParseIP(*config.Address); ip == nil {
			log.Fatalf("Failed to parse address from config: %s", ip)
		}
	}

	listenAddr := net.TCPAddr{
		IP:   ip,
		Port: int(*config.Port),
	}
	listener, err := net.ListenTCP("tcp", &listenAddr)
	if err != nil {
		log.Fatalf("Failed to listen on port: %s", err)
	}

	var identityPublic [32]byte
	curve25519.ScalarBaseMult(&identityPublic, &identity)
	identityString := strings.Replace(base32.StdEncoding.EncodeToString(identityPublic[:]), "=", "", -1)
	log.Printf("Started. Listening on port %d with identity %s", listener.Addr().(*net.TCPAddr).Port, identityString)

	server := NewServer(*baseDirectory, config.GetAllowRegistration())

	if *lifelineFd > -1 {
		lifeline := os.NewFile(uintptr(*lifelineFd), "lifeline")
		go func() {
			var buf [1]byte
			lifeline.Read(buf[:])
			os.Exit(255)
		}()
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Printf("Error accepting connection: %s", err)
			continue
		}

		go handleConnection(server, conn, &identity)
	}
}
Example #28
0
func (c *client) loadUI() error {
	c.ui.initUI()

	c.torAddress = "127.0.0.1:9050" // default for dev mode.
	if !c.dev && !c.detectTor() {
		if err := c.ui.torPromptUI(); err != nil {
			return err
		}
	}

	c.ui.loadingUI()

	stateFile := &disk.StateFile{
		Path: c.stateFilename,
		Rand: c.rand,
		Log: func(format string, args ...interface{}) {
			c.log.Printf(format, args...)
		},
	}

	var newAccount bool
	var err error
	if c.stateLock, err = stateFile.Lock(false /* don't create */); err == nil && c.stateLock == nil {
		c.ui.errorUI("State file locked by another process. Waiting for lock.", false)
		c.log.Errorf("Waiting for locked state file")

		for {
			if c.stateLock, err = stateFile.Lock(false /* don't create */); c.stateLock != nil {
				break
			}
			if err := c.ui.sleepUI(1 * time.Second); err != nil {
				return err
			}
		}
	} else if err == nil {
	} else if os.IsNotExist(err) {
		newAccount = true
	} else {
		c.ui.errorUI(err.Error(), true)
		if err := c.ui.ShutdownAndSuspend(); err != nil {
			return err
		}
	}

	if newAccount {
		pub, priv, err := ed25519.GenerateKey(rand.Reader)
		if err != nil {
			panic(err)
		}
		copy(c.priv[:], priv[:])
		copy(c.pub[:], pub[:])

		if c.disableV2Ratchet {
			c.randBytes(c.identity[:])
		} else {
			extra25519.PrivateKeyToCurve25519(&c.identity, priv)
		}
		curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

		c.groupPriv, err = bbssig.GenerateGroup(rand.Reader)
		if err != nil {
			panic(err)
		}
		pw, err := c.ui.createPassphraseUI()
		if err != nil {
			return err
		}
		c.ui.createErasureStorage(pw, stateFile)
		if err := c.ui.createAccountUI(); err != nil {
			return err
		}
		newAccount = true
	} else {
		// First try with zero key.
		err := c.loadState(stateFile, "")
		for err == disk.BadPasswordError {
			// That didn't work, try prompting for a key.
			err = c.ui.keyPromptUI(stateFile)
		}
		if err == errInterrupted {
			return err
		}
		if err != nil {
			// Fatal error loading state. Abort.
			c.ui.errorUI(err.Error(), true)
			if err := c.ui.ShutdownAndSuspend(); err != nil {
				return err
			}
		}
	}

	if newAccount {
		c.stateLock, err = stateFile.Lock(true /* create */)
		if err != nil {
			err = errors.New("Failed to create state file: " + err.Error())
		} else if c.stateLock == nil {
			err = errors.New("Failed to obtain lock on created state file")
		}
		if err != nil {
			c.ui.errorUI(err.Error(), true)
			if err := c.ui.ShutdownAndSuspend(); err != nil {
				return err
			}
		}
		c.lastErasureStorageTime = time.Now()
	}

	c.writerChan = make(chan disk.NewState)
	c.writerDone = make(chan struct{})
	c.fetchNowChan = make(chan chan bool, 1)

	// Start disk and network workers.
	go stateFile.StartWriter(c.writerChan, c.writerDone)
	go c.transact()
	if newAccount {
		c.save()
	}

	// Start any pending key exchanges.
	for _, contact := range c.contacts {
		if len(contact.pandaKeyExchange) == 0 {
			continue
		}
		c.pandaWaitGroup.Add(1)
		contact.pandaShutdownChan = make(chan struct{})
		go c.runPANDA(contact.pandaKeyExchange, contact.id, contact.name, contact.pandaShutdownChan)
	}

	c.ui.mainUI()

	return nil
}
Example #29
0
File: cli.go Project: joncave/pond
func (c *cliClient) processCommand(cmd interface{}) (shouldQuit bool) {
	// First commands that might start a subprocess that needs terminal
	// control.
	switch cmd.(type) {
	case composeCommand:
		if contact, ok := c.currentObj.(*Contact); ok {
			c.compose(contact, nil, nil)
		} else {
			c.Printf("%s Select contact first\n", termWarnPrefix)
		}

	case contactsCommand:
		c.showContacts()
	case editCommand:
		if draft, ok := c.currentObj.(*Draft); ok {
			c.compose(nil, draft, nil)
		} else {
			c.Printf("%s Select draft first\n", termWarnPrefix)
		}

	case replyCommand:
		msg, ok := c.currentObj.(*InboxMessage)
		if !ok {
			c.Printf("%s Select inbox message first\n", termWarnPrefix)
			return
		}
		c.compose(c.contacts[msg.from], nil, msg)

	default:
		goto Handle
	}
	return

Handle:
	// The command won't need to start subprocesses with terminal control
	// so we can start watching for Ctrl-C again.
	c.termWrapper.Restart()

	switch cmd := cmd.(type) {
	case clearCommand:
		c.Printf("\x1b[2J")

	case helpCommand:
		if cmd.ShowAll {
			c.input.showHelp(0, true)
			return
		}

		switch c.currentObj.(type) {
		case *Contact:
			c.input.showHelp(contextContact, false)
		case *Draft:
			c.input.showHelp(contextDraft, false)
		case *InboxMessage:
			c.input.showHelp(contextInbox, false)
		case *queuedMessage:
			c.input.showHelp(contextOutbox, false)
		default:
			c.input.showHelp(0, false)
		}

	case tagCommand:
		if len(cmd.tag) == 0 {
			c.showState()
			return
		}
		cliId, ok := cliIdFromString(cmd.tag)
		if !ok {
			c.Printf("%s Bad tag\n", termWarnPrefix)
			return
		}
		for _, msg := range c.inbox {
			if msg.cliId == cliId {
				c.setCurrentObject(msg)
				return
			}
		}
		for _, msg := range c.outbox {
			if msg.cliId == cliId {
				c.setCurrentObject(msg)
				return
			}
		}
		for _, msg := range c.drafts {
			if msg.cliId == cliId {
				c.setCurrentObject(msg)
				return
			}
		}
		for _, contact := range c.contacts {
			if contact.cliId == cliId {
				c.setCurrentObject(contact)
				return
			}
		}
		c.Printf("%s Unknown tag\n", termWarnPrefix)

	case logCommand:
		n := 15
		if l := len(c.log.entries); l < n {
			n = l
		}
		for _, entry := range c.log.entries[len(c.log.entries)-n:] {
			c.Printf("%s (%s) %s\n", termHeaderPrefix, entry.Format(logTimeFormat), terminalEscape(entry.s, false))
		}

	case transactNowCommand:
		c.Printf("%s Triggering immediate network transaction.\n", termPrefix)
		select {
		case c.fetchNowChan <- nil:
		default:
		}

	case closeCommand:
		c.setCurrentObject(nil)

	case quitCommand:
		c.ShutdownAndSuspend()
		c.Printf("Goodbye!\n")
		shouldQuit = true
		return

	case deleteCommand:
		if c.currentObj == nil {
			c.Printf("%s Select object first\n", termWarnPrefix)
			return
		}
		switch o := c.currentObj.(type) {
		case *Draft:
			delete(c.drafts, o.id)
			c.save()
			c.setCurrentObject(nil)
		case *Contact:
			c.maybeDeleteContact(o)
			// maybeDeleteContact may need confirmation so
			// setCurrentObject is handled in there.
		default:
			c.Printf("%s Cannot delete current object\n", termWarnPrefix)
		}

	case sendCommand:
		draft, ok := c.currentObj.(*Draft)
		if !ok {
			c.Printf("%s Select draft first\n", termWarnPrefix)
			return
		}
		to := c.contacts[draft.to]
		var myNextDH []byte
		if to.ratchet == nil {
			var nextDHPub [32]byte
			curve25519.ScalarBaseMult(&nextDHPub, &to.currentDHPrivate)
			myNextDH = nextDHPub[:]
		}

		if len(draft.body) == 0 {
			// Zero length bodies are ACKs.
			draft.body = " "
		}
		id := c.randId()
		var inReplyTo *uint64
		if r := draft.inReplyTo; r != 0 {
			inReplyTo = proto.Uint64(r)
		}
		err := c.send(to, &pond.Message{
			Id:               proto.Uint64(id),
			Time:             proto.Int64(c.Now().Unix()),
			Body:             []byte(draft.body),
			BodyEncoding:     pond.Message_RAW.Enum(),
			InReplyTo:        inReplyTo,
			MyNextDh:         myNextDH,
			Files:            draft.attachments,
			DetachedFiles:    draft.detachments,
			SupportedVersion: proto.Int32(protoVersion),
		})
		if err != nil {
			c.log.Errorf("%s Error sending: %s\n", termErrPrefix, err)
			return
		}
		if draft.inReplyTo != 0 {
			for _, msg := range c.inbox {
				if msg.message != nil && msg.message.GetId() == draft.inReplyTo {
					msg.acked = true
					break
				}
			}
		}
		delete(c.drafts, draft.id)
		c.setCurrentObject(nil)
		for _, msg := range c.outbox {
			if msg.id == id {
				if msg.cliId == invalidCliId {
					msg.cliId = c.newCliId()
				}
				c.Printf("%s Created new outbox entry %s%s%s\n", termInfoPrefix, termCliIdStart, msg.cliId.String(), termReset)
				c.setCurrentObject(msg)
				c.showQueueState()
				break
			}
		}
		c.save()

	case abortCommand:
		msg, ok := c.currentObj.(*queuedMessage)
		if !ok {
			c.Printf("%s Select outbox message first\n", termErrPrefix)
			return
		}

		c.queueMutex.Lock()
		index := c.indexOfQueuedMessage(msg)
		if index == -1 || msg.sending {
			c.queueMutex.Unlock()
			c.Printf("%s Too Late to Abort!\n", termErrPrefix)
			return
		}

		c.removeQueuedMessage(index)
		c.queueMutex.Unlock()

		c.deleteOutboxMsg(msg.id)
		draft := c.outboxToDraft(msg)
		c.drafts[draft.id] = draft
		if draft.cliId == invalidCliId {
			draft.cliId = c.newCliId()
		}

		c.Printf("%s Aborted sending %s%s%s and moved to Drafts as %s%s%s\n", termInfoPrefix, termCliIdStart, msg.cliId.String(), termReset, termCliIdStart, draft.cliId.String(), termReset)
		c.save()
		c.setCurrentObject(draft)

	case ackCommand:
		msg, ok := c.currentObj.(*InboxMessage)
		if !ok {
			c.Printf("%s Select inbox message first\n", termWarnPrefix)
			return
		}
		if msg.acked {
			c.Printf("%s Message has already been acknowledged\n", termWarnPrefix)
			return
		}
		msg.acked = true
		c.sendAck(msg)
		c.showQueueState()

	case showCommand:
		if c.currentObj == nil {
			c.Printf("Select object first\n")
			return
		}
		switch o := c.currentObj.(type) {
		case *queuedMessage:
			c.showOutbox(o)
		case *InboxMessage:
			c.showInbox(o)
		case *Draft:
			c.showDraft(o)
		case *Contact:
			c.showContact(o)
		default:
			c.Printf("%s Cannot show the current object\n", termWarnPrefix)
		}

	case showOutboxSummaryCommand:
		c.showOutboxSummary()

	case showInboxSummaryCommand:
		c.showInboxSummary()

	case showDraftsSummaryCommand:
		c.showDraftsSummary()

	case showQueueStateCommand:
		c.showQueueState()

	case statusCommand:
		c.showState()

	case attachCommand:
		draft, ok := c.currentObj.(*Draft)
		if !ok {
			c.Printf("%s Select draft first\n", termWarnPrefix)
		}
		contents, size, err := openAttachment(cmd.Filename)
		if err != nil {
			c.Printf("%s Failed to open file: %s\n", termErrPrefix, terminalEscape(err.Error(), false))
			return
		}
		if size > 0 {
			c.Printf("%s File is too large (%d bytes) to attach. Use the 'upload' or 'save-encrypted' commands to encrypt the file, include just the keys in the message and either upload or save the ciphertext\n", termErrPrefix, size)
			return
		}

		base := filepath.Base(cmd.Filename)
		a := &pond.Message_Attachment{
			Filename: proto.String(base),
			Contents: contents,
		}
		draft.attachments = append(draft.attachments, a)
		c.Printf("%s Attached '%s' (%d bytes)\n", termPrefix, terminalEscape(base, false), len(contents))
		c.printDraftSize(draft)

	case uploadCommand:
		draft, ok := c.currentObj.(*Draft)
		if !ok {
			c.Printf("%s Select draft first\n", termWarnPrefix)
			return
		}

		base := filepath.Base(cmd.Filename)
		id := c.randId()
		c.Printf("%s Padding, encrypting and uploading '%s' to home server (Ctrl-C to abort):\n", termPrefix, terminalEscape(base, false))
		cancelThunk := c.startUpload(id, cmd.Filename)

		if detachment, ok := c.runBackgroundProcess(id, cancelThunk); ok {
			draft.detachments = append(draft.detachments, detachment)
		}

	case downloadCommand:
		msg, ok := c.currentObj.(*InboxMessage)
		if !ok {
			c.Printf("%s Select inbox message\n", termWarnPrefix)
			return
		}
		i, ok := c.prepareSubobjectCommand(cmd.Number, len(msg.message.DetachedFiles), "detachment")
		if !ok {
			return
		}
		id := c.randId()

		c.Printf("%s Downloading and decrypting detachment (Ctrl-C to abort):\n", termPrefix)
		cancelThunk := c.startDownload(id, cmd.Filename, msg.message.DetachedFiles[i])

		c.runBackgroundProcess(id, cancelThunk)

	case saveCommand:
		msg, ok := c.currentObj.(*InboxMessage)
		if !ok {
			c.Printf("%s Select inbox message\n", termWarnPrefix)
			return
		}
		i, ok := c.prepareSubobjectCommand(cmd.Number, len(msg.message.Files), "attachment")
		if !ok {
			return
		}

		if err := ioutil.WriteFile(cmd.Filename, msg.message.Files[i].GetContents(), 0600); err != nil {
			c.Printf("%s Failed to write file: %s\n", termErrPrefix, terminalEscape(err.Error(), false))
		} else {
			c.Printf("%s Wrote file\n", termPrefix)
		}

	case removeCommand:
		draft, ok := c.currentObj.(*Draft)
		if !ok {
			c.Printf("%s Select draft first\n", termWarnPrefix)
		}
		i, ok := c.prepareSubobjectCommand(cmd.Number, len(draft.attachments)+len(draft.detachments), "attachment")
		if !ok {
			return
		}

		if i < len(draft.attachments) {
			draft.attachments = append(draft.attachments[:i], draft.attachments[i+1:]...)
			return
		}
		i -= len(draft.attachments)
		draft.detachments = append(draft.detachments[:i], draft.detachments[i+1:]...)

	case newContactCommand:
		for _, contact := range c.contacts {
			if contact.name == cmd.Name {
				c.Printf("%s A contact with that name already exists.\n", termErrPrefix)
				return
			}
		}

		c.Printf("Enter shared secret with contact, or hit enter to generate, print and use a random one\n")
		sharedSecret, err := c.term.ReadPassword("secret: ")
		if err != nil {
			panic(err)
		}
		if len(sharedSecret) == 0 {
			var secret [16]byte
			c.randBytes(secret[:])
			sharedSecret = fmt.Sprintf("%x", secret[:])
			c.Printf("%s Shared secret: %s\n", termPrefix, sharedSecret)
		}

		contact := &Contact{
			name:      cmd.Name,
			isPending: true,
			id:        c.randId(),
			cliId:     c.newCliId(),
		}

		c.newKeyExchange(contact)

		stack := &panda.CardStack{
			NumDecks: 1,
		}
		secret := panda.SharedSecret{
			Secret: sharedSecret,
			Cards:  *stack,
		}

		mp := c.newMeetingPlace()

		c.contacts[contact.id] = contact
		kx, err := panda.NewKeyExchange(c.rand, mp, &secret, contact.kxsBytes)
		if err != nil {
			panic(err)
		}
		kx.Testing = c.testing
		contact.pandaKeyExchange = kx.Marshal()
		contact.kxsBytes = nil

		c.save()
		c.pandaWaitGroup.Add(1)
		contact.pandaShutdownChan = make(chan struct{})
		go c.runPANDA(contact.pandaKeyExchange, contact.id, contact.name, contact.pandaShutdownChan)
		c.Printf("%s Key exchange running in background.\n", termPrefix)

	case renameCommand:
		if contact, ok := c.currentObj.(*Contact); ok {
			c.renameContact(contact, cmd.NewName)
		} else {
			c.Printf("%s Select contact first\n", termWarnPrefix)
		}

	default:
		panic(fmt.Sprintf("Unhandled command: %#v", cmd))
	}

	return
}
Example #30
0
func runScript(t *testing.T, s script) {
	server := NewTestServer(s.setupDir)
	defer server.Close()

	identities := make([][32]byte, s.numPlayers)
	publicIdentities := make([][32]byte, s.numPlayers)
	for i := range identities {
		io.ReadFull(rand.Reader, identities[i][:])
		curve25519.ScalarBaseMult(&publicIdentities[i], &identities[i])
	}

	groupPrivateKeys := make([]*bbssig.PrivateKey, s.numPlayersWithAccounts)
	for i := range groupPrivateKeys {
		var err error
		groupPrivateKeys[i], err = bbssig.GenerateGroup(rand.Reader)
		if err != nil {
			panic(err)
		}

		conn := server.Dial(&identities[i], &publicIdentities[i])
		if err := conn.WriteProto(&pond.Request{
			NewAccount: &pond.NewAccount{
				Generation: proto.Uint32(0),
				Group:      groupPrivateKeys[i].Group.Marshal(),
			},
		}); err != nil {
			t.Fatal(err)
		}

		reply := new(pond.Reply)
		if err := conn.ReadProto(reply); err != nil {
			t.Fatalf("Error while reading reply from server: %s", err)
		}
		if reply.AccountCreated == nil {
			t.Fatalf("Failed to create 1st account: %s", err)
		}
		conn.Close()
	}

	state := &scriptState{
		identities:       identities,
		publicIdentities: publicIdentities,
		groupPrivateKeys: groupPrivateKeys,
		testServer:       server,
	}

	for _, a := range s.actions {
		conn := server.Dial(&identities[a.player], &publicIdentities[a.player])

		req := a.request
		if a.buildRequest != nil {
			req = a.buildRequest(state)
		}
		if err := conn.WriteProto(req); err != nil {
			t.Fatal(err)
		}

		reply := new(pond.Reply)
		if err := conn.ReadProto(reply); err != nil {
			t.Fatal(err)
		}
		if a.validate != nil {
			a.validate(t, reply)
		}

		if len(a.payload) > 0 {
			_, err := conn.Write(a.payload)
			if err != nil {
				t.Fatalf("Failed to write payload: %s", err)
			}
		}
		if a.payloadSize > 0 {
			fromServer := make([]byte, a.payloadSize)
			if _, err := io.ReadFull(conn, fromServer); err != nil {
				t.Errorf("Failed to read payload: %s", err)
			}
			if a.validatePayload != nil {
				a.validatePayload(t, fromServer)
			}
		}
		conn.Close()
	}
}