Exemple #1
0
func main() {
	message := []byte("Gophers of the world, unite!")

	alicePublic, alicePrivate, err := box.GenerateKey(rand.Reader)
	if err != nil {
		fmt.Printf("Failed to generate keypair for Alice: %v\n", err)
		return
	}

	bobPublic, bobPrivate, err := box.GenerateKey(rand.Reader)
	if err != nil {
		fmt.Printf("Failed to generate keypair for Bob: %v\n", err)
		return
	}

	encrypted := box.Seal(nil, message, &nonce, bobPublic, alicePrivate)

	decrypted, ok := box.Open(nil, encrypted, &nonce, alicePublic, bobPrivate)
	if !ok {
		fmt.Println("Decryption failed.\n")
		return
	}

	if !bytes.Equal(message, decrypted) {
		fmt.Println("Message recovered failed.\n")
		return
	}

	// Nonce should only be used once.
	updateNonce(&nonce)

	fmt.Println("OK")
}
Exemple #2
0
func main() {
	var rs [256][4][]byte
	for i := range rs {
		pk1, _, err := box.GenerateKey(rand.Reader)
		if err != nil {
			panic(err)
		}
		_, sk2, err := box.GenerateKey(rand.Reader)
		if err != nil {
			panic(err)
		}
		var n [24]byte // zero nonce
		m := make([]byte, i)
		if _, err := io.ReadFull(rand.Reader, m[:]); err != nil {
			panic(err)
		}
		b := box.Seal(nil, m, &n, pk1, sk2)
		rs[i][0] = pk1[:]
		rs[i][1] = sk2[:]
		rs[i][2] = m
		rs[i][3] = b
	}
	out, err := json.MarshalIndent(rs, "", "")
	if err != nil {
		panic(err)
	}
	fmt.Print("module.exports = ")
	fmt.Print(string(out))
	fmt.Println(";")
}
Exemple #3
0
func (c *client) send(to *Contact, message *pond.Message) error {
	var nonce [24]byte
	c.randBytes(nonce[:])

	messageBytes, err := proto.Marshal(message)
	if err != nil {
		return err
	}

	if len(messageBytes) > pond.MaxSerializedMessage {
		return errors.New("message too large")
	}

	plaintext := make([]byte, pond.MaxSerializedMessage+4)
	binary.LittleEndian.PutUint32(plaintext, uint32(len(messageBytes)))
	copy(plaintext[4:], messageBytes)
	c.randBytes(plaintext[4+len(messageBytes):])

	sealed := make([]byte, len(plaintext)+box.Overhead+len(nonce))
	copy(sealed, nonce[:])
	box.Seal(sealed[len(nonce):len(nonce)], plaintext, &nonce, &to.theirCurrentDHPublic, &to.lastDHPrivate)

	sha := sha256.New()
	sha.Write(sealed)
	digest := sha.Sum(nil)
	sha.Reset()
	groupSig, err := to.myGroupKey.Sign(c.rand, digest, sha)
	if err != nil {
		return err
	}

	request := &pond.Request{
		Deliver: &pond.Delivery{
			To:         to.theirIdentityPublic[:],
			Signature:  groupSig,
			Generation: proto.Uint32(to.generation),
			Message:    sealed,
		},
	}
	out := &queuedMessage{
		request: request,
		id:      *message.Id,
		to:      to.id,
		server:  to.theirServer,
		message: message,
		created: time.Unix(*message.Time, 0),
	}
	c.enqueue(out)
	if len(message.Body) > 0 {
		c.outboxUI.Add(*message.Id, to.name, out.created.Format(shortTimeFormat), indicatorRed)
	}
	c.outbox = append(c.outbox, out)

	return nil
}
Exemple #4
0
func (cr *Crypto) Encrypt(data []byte) ([]byte, error) {
	ephemeralPublicKey, ephemeralPrivateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		return nil, err
	}
	ciphertext := box.Seal(nil, data, &cr.nonce, &cr.publicKey, ephemeralPrivateKey)
	output := make([]byte, 32+len(ciphertext))

	copy(output[0:32], ephemeralPublicKey[0:32])
	copy(output[32:], ciphertext)

	return output, nil
}
Exemple #5
0
func (enc *boxEncoder) newCaveatId(cav Caveat, rootKey []byte, thirdPartyPub *PublicKey) (*caveatId, error) {
	var nonce [NonceLen]byte
	if _, err := rand.Read(nonce[:]); err != nil {
		return nil, fmt.Errorf("cannot generate random number for nonce: %v", err)
	}
	plain := caveatIdRecord{
		RootKey:   rootKey,
		Condition: cav.Condition,
	}
	plainData, err := json.Marshal(&plain)
	if err != nil {
		return nil, fmt.Errorf("cannot marshal %#v: %v", &plain, err)
	}
	sealed := box.Seal(nil, plainData, &nonce, (*[32]byte)(thirdPartyPub), (*[32]byte)(&enc.key.Private))
	return &caveatId{
		ThirdPartyPublicKey: thirdPartyPub[:],
		FirstPartyPublicKey: enc.key.Public[:],
		Nonce:               nonce[:],
		Id:                  base64.StdEncoding.EncodeToString(sealed),
	}, nil
}
Exemple #6
0
// send encrypts |message| and enqueues it for transmission.
func (c *client) send(to *Contact, message *pond.Message) error {
	messageBytes, err := proto.Marshal(message)
	if err != nil {
		return err
	}

	if len(messageBytes) > pond.MaxSerializedMessage {
		return errors.New("message too large")
	}

	// All messages are padded to the maximum length.
	plaintext := make([]byte, pond.MaxSerializedMessage+4)
	binary.LittleEndian.PutUint32(plaintext, uint32(len(messageBytes)))
	copy(plaintext[4:], messageBytes)
	c.randBytes(plaintext[4+len(messageBytes):])

	// The message is encrypted to an ephemeral key so that the sending
	// client can choose not to store it and then cannot decrypt it once
	// sent.

	//            +---------------------+            +---...
	// outerNonce | ephemeral DH public | innerNonce | message
	// (24 bytes) |                     | (24 bytes) |
	//            +---------------------+            +---....

	sealedLen := ephemeralBlockLen + nonceLen + len(plaintext) + box.Overhead
	sealed := make([]byte, sealedLen)
	var outerNonce [24]byte
	c.randBytes(outerNonce[:])
	copy(sealed, outerNonce[:])
	x := sealed[nonceLen:]

	public, private, err := box.GenerateKey(c.rand)
	if err != nil {
		return err
	}
	box.Seal(x[:0], public[:], &outerNonce, &to.theirCurrentDHPublic, &to.lastDHPrivate)
	x = x[len(public)+box.Overhead:]

	var innerNonce [24]byte
	c.randBytes(innerNonce[:])
	copy(x, innerNonce[:])
	x = x[nonceLen:]
	box.Seal(x[:0], plaintext, &innerNonce, &to.theirCurrentDHPublic, private)

	sha := sha256.New()
	sha.Write(sealed)
	digest := sha.Sum(nil)
	sha.Reset()
	groupSig, err := to.myGroupKey.Sign(c.rand, digest, sha)
	if err != nil {
		return err
	}

	request := &pond.Request{
		Deliver: &pond.Delivery{
			To:         to.theirIdentityPublic[:],
			Signature:  groupSig,
			Generation: proto.Uint32(to.generation),
			Message:    sealed,
		},
	}
	out := &queuedMessage{
		request: request,
		id:      *message.Id,
		to:      to.id,
		server:  to.theirServer,
		message: message,
		created: time.Unix(*message.Time, 0),
	}
	c.enqueue(out)
	if len(message.Body) > 0 {
		c.outboxUI.Add(*message.Id, to.name, out.created.Format(shortTimeFormat), indicatorRed)
	}
	c.outbox = append(c.outbox, out)

	return nil
}
Exemple #7
0
func (s *server) pump() {
	rotateMinuteKey := time.NewTicker(30 * time.Second)

	for {
		select {
		case packet := <-s.packetIn:
			if s.checkHello(packet.buf) {
				resp := freelist.Packets.Get()
				resp, scratch := resp[:200], resp[200:]

				pkey, skey, err := box.GenerateKey(rand.Reader)
				if err != nil {
					panic("Ran out of randomness")
				}

				// Client short-term public key
				copy(scratch, packet.buf[40:40+32])
				// Server short-term secret key
				copy(scratch[32:], skey[:])

				// minute-key secretbox nonce
				var nonce [24]byte
				copy(nonce[:], minuteNoncePrefix)
				randBytes(nonce[len(minuteNoncePrefix):])

				secretbox.Seal(scratch[:64], scratch[:64], &nonce, &s.minuteKey)

				// Compressed cookie nonce
				copy(scratch[48:64], nonce[len(minuteNoncePrefix):])
				// Server short-term public key
				copy(scratch[16:48], pkey[:])

				var clientKey [32]byte
				copy(clientKey[:], packet.buf[40:40+32])

				// Cookie box nonce
				copy(nonce[:], cookieNoncePrefix)
				randBytes(nonce[len(cookieNoncePrefix):])

				box.Seal(resp[:56], scratch[16:16+128], &nonce, &clientKey, &s.longTermSecretKey)

				// Packet header, with extensions swapped.
				copy(resp, cookieMagic)
				copy(resp[8:], packet.buf[24:24+16])
				copy(resp[24:], packet.buf[8:8+16])
				copy(resp[40:], nonce[8:])

				s.sock.WriteTo(resp, packet.Addr)
				freelist.Packets.Put(resp)

			} else if serverShortTermKey, domain, valid := s.checkInitiate(packet.buf); valid {
				clientShortTermKey := packet.buf[40 : 40+32]
				clientLongTermKey := packet.buf[176 : 176+32]
				if ch, ok := s.conns[string(clientShortTermKey)]; ok {
					// Forward the Initiate to the conn. Because
					// checkInitiate replaces the box in the Initiate
					// packet with its plaintext, and because pump has
					// done all the crypto verification, conn can
					// ignore anything not relevant to maintaining
					// correct stream state.
					ch <- packet
				} else if s.listen {
					// This is a new client initiating. Construct a
					// conn and wait for someone to Accept() it.
					c := newConn(s.sock, clientLongTermKey, clientShortTermKey, serverShortTermKey, domain)
					// TODO: accept timeout or something.
					s.newConn <- c
					s.conns[string(clientShortTermKey)] = c.packetIn
				}
			}

		case <-s.stopListen:
			s.listen = false
			close(s.newConn)
			// We hang onto the long term secret key and minute keys
			// for one full minute key rotation, so that we can still
			// decode retransmitted Initiate packets for a while. The
			// rotateMinuteKey case below will take care of final
			// cleanup.

		case <-rotateMinuteKey.C:
			if !s.listen && bytes.Equal(s.minuteKey[:], s.prevMinuteKey[:]) {
				// At least 30 seconds have passed since we stopped
				// listening, we can clear the key material and stop
				// refreshing minute keys.
				for i := 0; i < len(s.longTermSecretKey); i++ {
					s.minuteKey[i] = 0
					s.prevMinuteKey[i] = 0
					s.longTermSecretKey[i] = 0
				}
				rotateMinuteKey.Stop()
			} else {
				copy(s.prevMinuteKey[:], s.minuteKey[:])
				if s.listen {
					randBytes(s.minuteKey[:])
				}
			}
		}
	}
}
Exemple #8
0
func (c *client) send(to *Contact, message *pond.Message) error {
	messageBytes, err := proto.Marshal(message)
	if err != nil {
		return err
	}

	if len(messageBytes) > pond.MaxSerializedMessage {
		return errors.New("message too large")
	}

	plaintext := make([]byte, pond.MaxSerializedMessage+4)
	binary.LittleEndian.PutUint32(plaintext, uint32(len(messageBytes)))
	copy(plaintext[4:], messageBytes)
	c.randBytes(plaintext[4+len(messageBytes):])

	var innerNonce [24]byte
	c.randBytes(innerNonce[:])
	var sealed, innerSealed []byte
	sealedLen := nonceLen + len(plaintext) + box.Overhead
	dhPrivate := &to.lastDHPrivate

	if to.supportedVersion >= 1 {
		public, private, err := box.GenerateKey(c.rand)
		if err != nil {
			return err
		}
		dhPrivate = private

		var outerNonce [24]byte
		c.randBytes(outerNonce[:])
		sealedLen += ephemeralBlockLen
		sealed = make([]byte, sealedLen)
		copy(sealed, outerNonce[:])
		box.Seal(sealed[nonceLen:nonceLen], public[:], &outerNonce, &to.theirCurrentDHPublic, &to.lastDHPrivate)
		innerSealed = sealed[ephemeralBlockLen:]
	} else {
		sealed = make([]byte, sealedLen)
		innerSealed = sealed
	}

	copy(innerSealed, innerNonce[:])
	box.Seal(innerSealed[nonceLen:nonceLen], plaintext, &innerNonce, &to.theirCurrentDHPublic, dhPrivate)

	sha := sha256.New()
	sha.Write(sealed)
	digest := sha.Sum(nil)
	sha.Reset()
	groupSig, err := to.myGroupKey.Sign(c.rand, digest, sha)
	if err != nil {
		return err
	}

	request := &pond.Request{
		Deliver: &pond.Delivery{
			To:         to.theirIdentityPublic[:],
			Signature:  groupSig,
			Generation: proto.Uint32(to.generation),
			Message:    sealed,
		},
	}
	out := &queuedMessage{
		request: request,
		id:      *message.Id,
		to:      to.id,
		server:  to.theirServer,
		message: message,
		created: time.Unix(*message.Time, 0),
	}
	c.enqueue(out)
	if len(message.Body) > 0 {
		c.outboxUI.Add(*message.Id, to.name, out.created.Format(shortTimeFormat), indicatorRed)
	}
	c.outbox = append(c.outbox, out)

	return nil
}
Exemple #9
0
// processSigningRequest is run on the main goroutine in response to a request
// from the network thread to apply a group signature to a message that is just
// about to be sent to the destination server.
func (c *client) processSigningRequest(sigReq signingRequest) {
	defer close(sigReq.resultChan)
	to := c.contacts[sigReq.msg.to]

	messageBytes, err := proto.Marshal(sigReq.msg.message)
	if err != nil {
		c.log.Printf("Failed to sign outgoing message: %s", err)
		return
	}

	if len(messageBytes) > pond.MaxSerializedMessage {
		c.log.Printf("Failed to sign outgoing message because it's too large")
		return
	}

	// All messages are padded to the maximum length.
	plaintext := make([]byte, pond.MaxSerializedMessage+4)
	binary.LittleEndian.PutUint32(plaintext, uint32(len(messageBytes)))
	copy(plaintext[4:], messageBytes)
	c.randBytes(plaintext[4+len(messageBytes):])

	var sealed []byte
	if to.ratchet != nil {
		sealed = to.ratchet.Encrypt(sealed, plaintext)
	} else {
		// The message is encrypted to an ephemeral key so that the sending
		// client can choose not to store it and then cannot decrypt it once
		// sent.

		//            +---------------------+            +---...
		// outerNonce | ephemeral DH public | innerNonce | message
		// (24 bytes) |                     | (24 bytes) |
		//            +---------------------+            +---....

		sealedLen := ephemeralBlockLen + nonceLen + len(plaintext) + box.Overhead
		sealed = make([]byte, sealedLen)
		var outerNonce [24]byte
		c.randBytes(outerNonce[:])
		copy(sealed, outerNonce[:])
		x := sealed[nonceLen:]

		public, private, err := box.GenerateKey(c.rand)
		if err != nil {
			c.log.Printf("Failed to generate key for outgoing message: %s", err)
			return
		}
		box.Seal(x[:0], public[:], &outerNonce, &to.theirCurrentDHPublic, &to.lastDHPrivate)
		x = x[len(public)+box.Overhead:]

		var innerNonce [24]byte
		c.randBytes(innerNonce[:])
		copy(x, innerNonce[:])
		x = x[nonceLen:]
		box.Seal(x[:0], plaintext, &innerNonce, &to.theirCurrentDHPublic, private)
	}

	sha := sha256.New()
	sha.Write(sealed)
	digest := sha.Sum(nil)
	sha.Reset()
	groupSig, err := to.myGroupKey.Sign(c.rand, digest, sha)
	if err != nil {
		c.log.Printf("Failed to sign outgoing message: %s", err)
		return
	}

	request := &pond.Request{
		Deliver: &pond.Delivery{
			To:         to.theirIdentityPublic[:],
			Signature:  groupSig,
			Generation: proto.Uint32(to.generation),
			Message:    sealed,
		},
	}

	sigReq.resultChan <- request
}
Exemple #10
0
/* Encrypt & write message
 * Note that there is no way to directly convert a Message into CipherMessage struct,
 *  but you can use this function to serialize one to any writer (e.g. file or network)
 */
func WriteCipherMessage(writer io.Writer, message *Message, from, to *Identity, permit string) error {
	newError := func(err error) error { return errors.New("Cannot encrypt message: " + err.Error()) }
	// need to fill: To, From, Hash, CipherKey, CipherChunkSize, Permit
	// generate a new symmetric key
	var key [32]byte
	_, err := rand.Read(key[:])
	if err != nil {
		return newError(err)
	}
	// determine appropriate ChunkSize
	// for now, just use 10K bytes
	chunkSize := int64(10240)
	chunkSizeString := strconv.Itoa(int(chunkSize))
	// calculate CipherText hash
	hasher := sha512.New()
	cipherWriter := NewCipherWriter(hasher, &key, chunkSize)
	err = message.Serialize(cipherWriter)
	if err != nil {
		return newError(err)
	}
	err = cipherWriter.Close()
	if err != nil {
		return newError(err)
	}
	cipherMessageSize := cipherWriter.written
	hashBytes := hasher.Sum([]byte{})
	hashString := base64.URLEncoding.EncodeToString(hashBytes)
	// encrypt key to CipherKey
	var nonce [24]byte
	_, err = rand.Read(nonce[:])
	if err != nil {
		return newError(err)
	}
	cipherKey := box.Seal(nil, key[:], &nonce, to.PublicKey, from.PrivateKey)
	cipherKey = append(nonce[:], cipherKey...)
	cipherKeyString := base64.URLEncoding.EncodeToString(cipherKey)
	// make header
	header := map[string]interface{}{
		"To":              KeyToString(to.PublicKey),
		"From":            KeyToString(from.PublicKey),
		"Hash":            hashString,
		"CipherKey":       cipherKeyString,
		"CipherChunkSize": chunkSizeString,
		"Permit":          permit,
	}
	headerBytes, err := json.Marshal(header)
	if err != nil {
		return newError(err)
	}

	// write!
	err = binary.Write(writer, binary.BigEndian, uint64(len(headerBytes)))
	if err != nil {
		return newError(err)
	}
	_, err = writer.Write(headerBytes)
	if err != nil {
		return newError(err)
	}
	err = binary.Write(writer, binary.BigEndian, uint64(cipherMessageSize))
	if err != nil {
		return newError(err)
	}
	cipherWriter.Reset()
	cipherWriter.Writer = writer
	err = message.Serialize(cipherWriter)
	if err != nil {
		return newError(err)
	}
	err = cipherWriter.Close()
	if err != nil {
		return newError(err)
	}
	return nil
}