Beispiel #1
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)
}
Beispiel #2
0
func main() {
	password := []byte("password")
	secretKey, err := NewSecret(password) // Use Scrypt to hash password
	if err != nil {
		log.Fatal("%v", err)
	}

	// Get a valid nonce, never before used.
	var nonce = getNonce()

	message := []byte("Gophers of the world, unite!")
	encrypted := secretbox.Seal(nil, message, &nonce, &secretKey.Key)
	out := make([]byte, len(secretKey.Salt)+len(encrypted))

	// Encrypted message is prepended salt (for decryption) and ciphertext
	copy(out, secretKey.Salt)
	copy(out[len(secretKey.Salt):], encrypted)

	// Only use the nonce once with this key.
	updateNonce(&nonce)

	err = ioutil.WriteFile("secretmessage", out, 0644)
	if err != nil {
		log.Fatal("%v", err)
	}

	updateNonce(&nonce)
}
Beispiel #3
0
func (kx *KeyExchange) exchange1() error {
	reply, err := kx.meetingPlace.Exchange(kx.Log, kx.meeting1[:], kx.message1[:], kx.ShutdownChan)
	if err != nil {
		return err
	}

	var peerDHPublic, encryptedPeerDHPublic [32]byte
	if len(reply) < len(encryptedPeerDHPublic) {
		return errors.New("panda: meeting point reply too small")
	}

	copy(encryptedPeerDHPublic[:], reply)
	rijndael.NewCipher(&kx.key).Decrypt(&peerDHPublic, &encryptedPeerDHPublic)

	curve25519.ScalarMult(&kx.sharedKey, &kx.dhPrivate, &peerDHPublic)

	paddedLen := kx.meetingPlace.Padding()
	padded := make([]byte, paddedLen-24 /* nonce */ -secretbox.Overhead)
	binary.LittleEndian.PutUint32(padded, uint32(len(kx.kxBytes)))
	copy(padded[4:], kx.kxBytes)
	if _, err := io.ReadFull(kx.rand, padded[4+len(kx.kxBytes):]); err != nil {
		return err
	}

	var nonce [24]byte
	if _, err := io.ReadFull(kx.rand, nonce[:]); err != nil {
		return err
	}

	kx.message2 = make([]byte, paddedLen)
	copy(kx.message2, nonce[:])
	secretbox.Seal(kx.message2[24:24], padded, &nonce, &kx.sharedKey)

	return nil
}
Beispiel #4
0
func main() {
	var rs [768][4][]byte
	for i := range rs {
		var k [32]byte
		var n [24]byte
		if _, err := io.ReadFull(rand.Reader, k[:]); err != nil {
			panic(err)
		}
		if _, err := io.ReadFull(rand.Reader, n[:]); err != nil {
			panic(err)
		}
		m := make([]byte, i)
		if _, err := io.ReadFull(rand.Reader, m[:]); err != nil {
			panic(err)
		}
		b := secretbox.Seal(nil, m, &n, &k)
		rs[i][0] = k[:]
		rs[i][1] = n[:]
		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(";")
}
Beispiel #5
0
func (sender *EncryptedTCPSender) Send(msg []byte) error {
	sender.Lock()
	defer sender.Unlock()
	encodedMsg := secretbox.Seal(nil, msg, &sender.state.nonce, sender.state.sessionKey)
	sender.state.advance()
	return sender.SimpleTCPSender.Send(encodedMsg)
}
Beispiel #6
0
func (s *Convergent) Put(key []byte, value []byte) error {
	nonce := s.makeNonce(key)
	box := secretbox.Seal(nil, value, nonce, s.secret)

	boxedkey := s.computeBoxedKey(key)
	err := s.untrusted.Put(boxedkey, box)
	return err
}
Beispiel #7
0
func encrypt(key, text []byte, r io.Reader) ([]byte, error) {
	nonce, err := newNonce(r)
	if err != nil {
		return nil, err
	}
	out := make([]byte, 0, len(nonce)+secretbox.Overhead+len(text))
	out = append(out, nonce[:]...)
	return secretbox.Seal(out, text, nonce, makeKey(key)), nil
}
Beispiel #8
0
func (c *Conn) encrypt(data []byte) []byte {
	if !c.writeKeyValid {
		return data
	}

	encrypted := secretbox.Seal(nil, data, &c.writeSequence, &c.writeKey)
	incSequence(&c.writeSequence)
	return encrypted
}
Beispiel #9
0
// entomb encrypts and *destroys* the statefile. The encrypted statefile is
// written to tombFile (with tombPath). The function log will be called during
// the process to give status updates. It returns the random key of the
// encrypted statefile and whether the process was successful. If unsuccessful,
// the original statefile will not be destroyed.
func (c *client) entomb(tombPath string, tombFile *os.File, log func(string, ...interface{})) (keyHex *[32]byte, ok bool) {
	log("Emtombing statefile to %s\n", tombPath)
	log("Stopping network processing...\n")
	if c.fetchNowChan != nil {
		close(c.fetchNowChan)
	}
	log("Stopping active key exchanges...\n")
	for _, contact := range c.contacts {
		if contact.pandaShutdownChan != nil {
			close(contact.pandaShutdownChan)
		}
	}
	log("Serialising state...\n")
	stateBytes := c.marshal()

	var key [32]byte
	c.randBytes(key[:])
	var nonce [24]byte
	log("Encrypting...\n")
	encrypted := secretbox.Seal(nil, stateBytes, &nonce, &key)

	log("Writing...\n")
	if _, err := tombFile.Write(encrypted); err != nil {
		log("Error writing: %s\n", err)
		return nil, false
	}
	log("Syncing...\n")
	if err := tombFile.Sync(); err != nil {
		log("Error syncing: %s\n", err)
		return nil, false
	}
	if err := tombFile.Close(); err != nil {
		log("Error closing: %s\n", err)
		return nil, false
	}

	readBack, err := ioutil.ReadFile(tombPath)
	if err != nil {
		log("Error rereading: %s\n", err)
		return nil, false
	}
	if !bytes.Equal(readBack, encrypted) {
		log("Contents of tomb file incorrect\n")
		return nil, false
	}

	log("The ephemeral key is: %x\n", key)
	log("You must write the ephemeral key down now! Store it somewhat erasable!\n")

	log("Erasing statefile... ")
	c.writerChan <- disk.NewState{stateBytes, false, true /* destruct */}
	<-c.writerDone
	log("done\n")

	return &key, true
}
Beispiel #10
0
// encrypt generates a random nonce and encrypts the input using
// NaCl's secretbox package. The nonce is prepended to the ciphertext.
// A sealed message will the same size as the original message plus
// secretbox.Overhead bytes long.
func encrypt(key *[keySize]byte, message []byte) ([]byte, error) {
	nonce, err := generateNonce()
	if err != nil {
		return nil, ErrEncrypt
	}

	out := make([]byte, len(nonce))
	copy(out, nonce[:])
	out = secretbox.Seal(out, message, nonce, key)
	return out, nil
}
Beispiel #11
0
// encrypt generates a random nonce and encrypts the input using
// NaCl's secretbox package. The nonce is prepended to the ciphertext.
func encrypt(key *[keySize]byte, in []byte) ([]byte, bool) {
	var out = make([]byte, nonceSize)
	nonce := newNonce()
	if nonce == nil {
		return nil, false
	}

	copy(out, nonce[:])
	out = secretbox.Seal(out, in, nonce, key)
	return out, true
}
Beispiel #12
0
func stateWriter(stateFilename string, key *[32]byte, salt *[sCryptSaltLen]byte, states chan []byte, done chan bool) {
	for {
		s, ok := <-states
		if !ok {
			close(done)
			return
		}

		length := uint32(len(s)) + 4
		for i := uint(17); i < 32; i++ {
			if n := (uint32(1) << i); n >= length {
				length = n
				break
			}
		}

		plaintext := make([]byte, length)
		copy(plaintext[4:], s)
		if _, err := io.ReadFull(rand.Reader, plaintext[len(s)+4:]); err != nil {
			panic(err)
		}
		binary.LittleEndian.PutUint32(plaintext, uint32(len(s)))

		var nonceSmear [24 * smearedCopies]byte
		if _, err := io.ReadFull(rand.Reader, nonceSmear[:]); err != nil {
			panic(err)
		}

		var nonce [24]byte
		for i := 0; i < smearedCopies; i++ {
			for j := 0; j < 24; j++ {
				nonce[j] ^= nonceSmear[24*i+j]
			}
		}

		ciphertext := secretbox.Seal(nil, plaintext, &nonce, key)

		out, err := os.Create(stateFilename)
		if err != nil {
			panic(err)
		}
		if _, err := out.Write(salt[:]); err != nil {
			panic(err)
		}
		if _, err := out.Write(nonceSmear[:]); err != nil {
			panic(err)
		}
		if _, err := out.Write(ciphertext); err != nil {
			panic(err)
		}
		out.Close()
	}
}
Beispiel #13
0
// Encrypt encrypts a message using XSalsa20-Poly1305 and outputs it to dst.
func (sb *secretBoxMode) Encrypt(dst []byte, src []byte, nonce []byte) {
	if len(dst) <= sb.Overhead() {
		panic("cryptstate: bad dst")
	}

	if len(nonce) != 24 {
		panic("cryptstate: bad nonce length")
	}

	noncePtr := (*[24]byte)(unsafe.Pointer(&nonce[0]))
	secretbox.Seal(dst[0:0], src, noncePtr, &sb.key)
}
Beispiel #14
0
func (m *secretboxMode) Encrypt(input []byte) []byte {
	var out []byte
	var nonce [24]byte

	n, err := io.ReadFull(rand.Reader, nonce[:])
	if n != len(nonce) || err != nil {
		panic("could not read from random number generator")
	}

	out = secretbox.Seal(out[:0], input, &nonce, &m.key)
	out = append(out, nonce[:]...)
	return out
}
Beispiel #15
0
// encrypt chunk & write, and increment this.Written
func (this *CipherWriter) encryptWriteChunk() error {
	// write nonce if it hasn't already been written
	if this.written == 0 {
		written, err := this.Writer.Write(this.Nonce[:])
		if err != nil {
			return err
		}
		this.written += int64(written)
	}
	// chunk
	cipherChunk := secretbox.Seal(nil, this.chunk, this.Nonce, this.Key)
	written, err := this.Writer.Write(cipherChunk)
	this.written += int64(written)
	return err
}
Beispiel #16
0
func (s *httpService) getNewBackendSticky() (*httputil.ClientConn, *http.Cookie) {
	backend, addr := s.connectBackend()
	if backend == nil {
		return nil, nil
	}

	var nonce [24]byte
	_, err := io.ReadFull(rand.Reader, nonce[:])
	if err != nil {
		panic(err)
	}
	out := make([]byte, len(nonce), len(nonce)+len(addr)+secretbox.Overhead)
	copy(out, nonce[:])
	out = secretbox.Seal(out, []byte(addr), &nonce, s.cookieKey)

	return backend, &http.Cookie{Name: stickyCookie, Value: base64.StdEncoding.EncodeToString(out), Path: "/"}
}
Beispiel #17
0
func padAndBox(key *[32]byte, body []byte) []byte {
	nonceSlice := deriveKey(key, string(body))
	var nonce [24]byte
	copy(nonce[:], nonceSlice)

	padded := make([]byte, bodySize-len(nonce)-secretbox.Overhead)
	padded[0] = byte(len(body))
	padded[1] = byte(len(body) >> 8)
	if n := copy(padded[2:], body); n < len(body) {
		panic("argument to padAndBox too large: " + strconv.Itoa(len(body)))
	}

	box := make([]byte, bodySize)
	copy(box, nonce[:])
	secretbox.Seal(box[len(nonce):len(nonce)], padded, &nonce, key)
	return box
}
Beispiel #18
0
// SealWithKey does the same thing as Seal, but a different key can be passed in.
func (s *Service) SealWithKey(value []byte, secretKey *[SecretKeyLength]byte) (*SealedBytes, error) {
	// check that we either initialized with a key or one was passed in
	if secretKey == nil {
		return nil, fmt.Errorf("secret key is nil")
	}

	// generate nonce
	nonce, err := generateNonce()
	if err != nil {
		return nil, fmt.Errorf("unable to generate nonce: %v", err)
	}

	// use nacl secret box to encrypt plaintext
	var encrypted []byte
	encrypted = secretbox.Seal(encrypted, value, nonce, secretKey)

	// return sealed ciphertext
	return &SealedBytes{
		Ciphertext: encrypted,
		Nonce:      nonce[:],
	}, nil
}
Beispiel #19
0
func (ne *NaClEncryptor) Bytes() ([]byte, error) {
	plaintext, err := ne.NonEncryptor.Bytes()
	if err != nil {
		return nil, err
	}
	// We carry the DF flag in the (unencrypted portion of the)
	// payload, rather than just extracting it from the packet headers
	// at the receiving end, since we do not trust routers not to mess
	// with headers. As we have different decryptors for non-DF and
	// DF, that would result in hard to track down packet drops due to
	// crypto errors.
	seqNoAndDF := ne.seqNo
	if ne.df {
		seqNoAndDF |= (1 << 63)
	}
	ciphertext := ne.buf
	binary.BigEndian.PutUint64(ciphertext[ne.prefixLen:], seqNoAndDF)
	binary.BigEndian.PutUint64(ne.nonce[16:24], seqNoAndDF)
	// Seal *appends* to ciphertext
	ciphertext = secretbox.Seal(ciphertext[:ne.prefixLen+8], plaintext, &ne.nonce, ne.sessionKey)
	ne.seqNo++
	return ciphertext, nil
}
Beispiel #20
0
func (c *Conn) Write(buf []byte) (n int, err error) {
	if c.writeBuffer == nil {
		c.writeBuffer = make([]byte, blockSize+2)
	}

	for len(buf) > 0 {
		m := len(buf)
		if m > blockSize-secretbox.Overhead {
			m = blockSize - secretbox.Overhead
		}
		l := len(secretbox.Seal(c.writeBuffer[2:2], buf[:m], &c.writeSequence, &c.writeKey))
		c.writeBuffer[0] = byte(l)
		c.writeBuffer[1] = byte(l >> 8)
		if _, err = c.conn.Write(c.writeBuffer[:2+l]); err != nil {
			return n, err
		}
		n += m
		buf = buf[m:]
		incSequence(&c.writeSequence)
	}

	return
}
Beispiel #21
0
func (ne *NaClEncryptor) Bytes() []byte {
	plaintext := ne.NonEncryptor.Bytes()
	offsetFlags := ne.offset | ne.flags
	ciphertext := ne.buf
	binary.BigEndian.PutUint16(ciphertext[ne.prefixLen:], offsetFlags)
	nonce := ne.nonce
	if nonce == nil {
		freshNonce, encodedNonce, err := EncodeNonce(ne.df)
		if err = ne.conn.CheckFatal(err); err != nil {
			return []byte{}
		}
		ne.conn.SendTCP(encodedNonce)
		ne.nonce = freshNonce
		nonce = freshNonce
	}
	offset := ne.offset
	SetNonceLow15Bits(nonce, offset)
	// Seal *appends* to ciphertext
	ciphertext = secretbox.Seal(ciphertext[:ne.prefixLen+2], plaintext, nonce, ne.conn.SessionKey)

	offset = (offset + 1) & ((1 << 15) - 1)
	if offset == 0 {
		// need a new nonce please
		ne.nonce = <-ne.nonceChan
	} else if offset == 1<<14 { // half way through range, send new nonce
		nonce, encodedNonce, err := EncodeNonce(ne.df)
		if err = ne.conn.CheckFatal(err); err != nil {
			return []byte{}
		}
		ne.nonceChan <- nonce
		ne.conn.SendTCP(encodedNonce)
	}
	ne.offset = offset

	return ciphertext
}
Beispiel #22
0
// SealAfterPrecomputation performs the same actions as Seal, but takes a
// shared key as generated by Precompute.
func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte {
	return secretbox.Seal(out, message, nonce, sharedKey)
}
Beispiel #23
0
// Seal appends an encrypted and authenticated copy of message to out, which
// will be Overhead bytes longer than the original and must not overlap. The
// nonce must be unique for each distinct message for a given pair of keys.
func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte {
	var sharedKey [32]byte
	Precompute(&sharedKey, peersPublicKey, privateKey)
	return secretbox.Seal(out, message, nonce, &sharedKey)
}
Beispiel #24
0
func saveEncrypted(rand io.Reader, c chan interface{}, out io.Writer, id uint64, inPath string, killChan chan bool) (*pond.Message_Detachment, error) {
	in, err := os.Open(inPath)
	if err != nil {
		return nil, errors.New("failed to open input: " + err.Error())
	}
	defer in.Close()

	var size int64
	if fileInfo, err := in.Stat(); err == nil {
		size = fileInfo.Size()
	}

	var key [32]byte
	var nonce [24]byte

	if _, err := io.ReadFull(rand, key[:]); err != nil {
		panic(err)
	}

	blockSize := defaultDetachmentBlockSize
	buf := make([]byte, blockSize)

	var fileSize, bytesOut uint64
	var eof bool
	var boxBuf []byte
	var lastUpdate time.Time

	for {
		if !eof {
			n, err := io.ReadFull(in, buf)
			switch err {
			case nil:
				break
			case io.ErrUnexpectedEOF, io.EOF:
				eof = true
			default:
				return nil, errors.New("failed to read from source file: " + err.Error())
			}
			fileSize += uint64(n)
		}
		boxBuf = secretbox.Seal(boxBuf[:0], buf, &nonce, &key)

		if _, err := out.Write(boxBuf); err != nil {
			return nil, errors.New("failed to write to destination: " + err.Error())
		}
		bytesOut += uint64(len(boxBuf))

		// Stop when we've read all of the file and have hit a power of
		// two.
		if eof && (bytesOut&(bytesOut-1)) == 0 {
			break
		}

		incNonce(&nonce)

		now := time.Now()
		if size > 0 && (lastUpdate.IsZero() || now.Sub(lastUpdate) > 500*time.Millisecond) {
			lastUpdate = now
			select {
			case c <- DetachmentProgress{
				id:    id,
				done:  fileSize,
				total: uint64(size),
			}:
				break
			default:
			}
		}

		select {
		case <-killChan:
			return nil, backgroundCanceledError
		default:
			break
		}
	}

	return &pond.Message_Detachment{
		Filename:   proto.String(filepath.Base(inPath)),
		Size:       proto.Uint64(fileSize),
		PaddedSize: proto.Uint64(bytesOut),
		ChunkSize:  proto.Uint32(uint32(blockSize)),
		Key:        key[:],
	}, nil
}
Beispiel #25
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[:])
				}
			}
		}
	}
}
Beispiel #26
0
func (sf *StateFile) StartWriter(states chan NewState, done chan struct{}) {
	for {
		newState, ok := <-states
		if !ok {
			close(done)
			return
		}

		s := newState.State

		length := uint32(len(s)) + 4
		for i := uint(17); i < 32; i++ {
			if n := (uint32(1) << i); n >= length {
				length = n
				break
			}
		}

		plaintext := make([]byte, length)
		copy(plaintext[4:], s)
		if _, err := io.ReadFull(sf.Rand, plaintext[len(s)+4:]); err != nil {
			panic(err)
		}
		binary.LittleEndian.PutUint32(plaintext, uint32(len(s)))

		smearCopies := int(sf.header.GetNonceSmearCopies())
		nonceSmear := make([]byte, 24*smearCopies)
		if _, err := io.ReadFull(sf.Rand, nonceSmear[:]); err != nil {
			panic(err)
		}

		var nonce [24]byte
		for i := 0; i < smearCopies; i++ {
			for j := 0; j < 24; j++ {
				nonce[j] ^= nonceSmear[24*i+j]
			}
		}

		if sf.Erasure != nil && newState.RotateErasureStorage {
			var newMask [erasureKeyLen]byte
			if _, err := io.ReadFull(sf.Rand, newMask[:]); err != nil {
				panic(err)
			}
			if err := sf.Erasure.Write(&sf.key, &newMask); err != nil {
				sf.Log("Failed to write new erasure value: %s", err)
			} else {
				copy(sf.mask[:], newMask[:])
			}
		}

		var effectiveKey [kdfKeyLen]byte
		for i := range effectiveKey {
			effectiveKey[i] = sf.mask[i] ^ sf.key[i]
		}
		ciphertext := secretbox.Seal(nil, plaintext, &nonce, &effectiveKey)

		// Open a new, temporary, statefile
		out, err := os.OpenFile(sf.Path+".tmp", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600)
		if err != nil {
			panic(err)
		}
		headerBytes, err := proto.Marshal(&sf.header)
		if err != nil {
			panic(err)
		}
		if _, err := out.Write(headerMagic[:]); err != nil {
			panic(err)
		}
		if err := binary.Write(out, binary.LittleEndian, uint32(len(headerBytes))); err != nil {
			panic(err)
		}
		if _, err := out.Write(headerBytes); err != nil {
			panic(err)
		}
		if _, err := out.Write(nonceSmear[:]); err != nil {
			panic(err)
		}
		if _, err := out.Write(ciphertext); err != nil {
			panic(err)
		}
		out.Sync()
		out.Close()

		// Remove any previous temporary statefile
		// (But this shouldn't ever happen?)
		if err := os.Remove(sf.Path + "~"); err != nil && !os.IsNotExist(err) {
			panic(err)
		}
		// Relink the old statefile to a temporary location
		if err := os.Rename(sf.Path, sf.Path+"~"); err != nil && !os.IsNotExist(err) {
			panic(err)
		}
		// Link the new statefile in place
		if err := os.Rename(sf.Path+".tmp", sf.Path); err != nil {
			panic(err)
		}
	}
}
Beispiel #27
0
func (sf *StateFile) StartWriter(states chan NewState, done chan struct{}) {
	for {
		newState, ok := <-states
		if !ok {
			close(done)
			return
		}

		if newState.Destruct {
			sf.Log("disk: Destruct command received.")
			var newMask [erasureKeyLen]byte
			if _, err := io.ReadFull(sf.Rand, newMask[:]); err != nil {
				panic(err)
			}
			if sf.Erasure != nil {
				if err := sf.Erasure.Write(&sf.key, &newMask); err != nil {
					sf.Log("disk: Error while clearing NVRAM: %s", err)
				}
				if err := sf.Erasure.Destroy(&sf.key); err != nil {
					sf.Log("disk: Error while deleting NVRAM: %s", err)
				}
			}
			out, _ := os.OpenFile(sf.Path, os.O_WRONLY, 0600)
			if out != nil {
				pos, _ := out.Seek(0, 2)
				out.Seek(0, 0)
				sf.Log("disk: writing %d zeros to statefile", pos)
				zeros := make([]byte, pos)
				if _, err := out.Write(zeros); err != nil {
					sf.Log("disk: error from Write: %s", err)
				}
				if err := out.Sync(); err != nil {
					sf.Log("disk: error from Sync: %s", err)
				}
				if err := out.Close(); err != nil {
					sf.Log("disk: error from Close: %s", err)
				}
			}
			if err := os.Remove(sf.Path); err != nil {
				sf.Log("disk: error from Remove: %s", err)
			}
			close(done)
			return
		}

		s := newState.State

		length := uint32(len(s)) + 4
		for i := uint(17); i < 32; i++ {
			if n := (uint32(1) << i); n >= length {
				length = n
				break
			}
		}

		plaintext := make([]byte, length)
		copy(plaintext[4:], s)
		if _, err := io.ReadFull(sf.Rand, plaintext[len(s)+4:]); err != nil {
			panic(err)
		}
		binary.LittleEndian.PutUint32(plaintext, uint32(len(s)))

		smearCopies := int(sf.header.GetNonceSmearCopies())
		nonceSmear := make([]byte, 24*smearCopies)
		if _, err := io.ReadFull(sf.Rand, nonceSmear[:]); err != nil {
			panic(err)
		}

		var nonce [24]byte
		for i := 0; i < smearCopies; i++ {
			for j := 0; j < 24; j++ {
				nonce[j] ^= nonceSmear[24*i+j]
			}
		}

		if sf.Erasure != nil && newState.RotateErasureStorage {
			var newMask [erasureKeyLen]byte
			if _, err := io.ReadFull(sf.Rand, newMask[:]); err != nil {
				panic(err)
			}
			if err := sf.Erasure.Write(&sf.key, &newMask); err != nil {
				sf.Log("Failed to write new erasure value: %s", err)
			} else {
				copy(sf.mask[:], newMask[:])
			}
		}

		var effectiveKey [kdfKeyLen]byte
		for i := range effectiveKey {
			effectiveKey[i] = sf.mask[i] ^ sf.key[i]
		}
		ciphertext := secretbox.Seal(nil, plaintext, &nonce, &effectiveKey)

		// Open a new, temporary, statefile
		out, err := os.OpenFile(sf.Path+".tmp", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600)
		if err != nil {
			panic(err)
		}
		headerBytes, err := proto.Marshal(&sf.header)
		if err != nil {
			panic(err)
		}
		if _, err := out.Write(headerMagic[:]); err != nil {
			panic(err)
		}
		if err := binary.Write(out, binary.LittleEndian, uint32(len(headerBytes))); err != nil {
			panic(err)
		}
		if _, err := out.Write(headerBytes); err != nil {
			panic(err)
		}
		if _, err := out.Write(nonceSmear[:]); err != nil {
			panic(err)
		}
		if _, err := out.Write(ciphertext); err != nil {
			panic(err)
		}
		out.Sync()

		var newFd int

		// If we had a lock on the old state file then we need to also
		// lock the new file. First we lock the temp file.
		sf.lockFdMutex.Lock()
		if sf.lockFd != nil {
			newFd, err = syscall.Dup(int(out.Fd()))
			if err != nil {
				panic(err)
			}
			if err := syscall.Flock(newFd, syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
				panic(err)
			}
		}
		sf.lockFdMutex.Unlock()
		out.Close()

		// Remove any previous temporary statefile
		// (But this shouldn't ever happen?)
		if err := os.Remove(sf.Path + "~"); err != nil && !os.IsNotExist(err) {
			panic(err)
		}
		// Relink the old statefile to a temporary location
		if err := os.Rename(sf.Path, sf.Path+"~"); err != nil && !os.IsNotExist(err) {
			panic(err)
		}
		// Link the new statefile in place
		if err := os.Rename(sf.Path+".tmp", sf.Path); err != nil {
			panic(err)
		}
		// Remove the old file.
		os.Remove(sf.Path + "~")

		sf.lockFdMutex.Lock()
		if sf.lockFd != nil {
			// Duplicate the new file descriptor over the old one.
			// This will unlock the old inode.
			if err := syscall.Dup2(newFd, *sf.lockFd); err != nil {
				panic(err)
			}
			syscall.Close(newFd)
		}
		sf.lockFdMutex.Unlock()
	}
}
Beispiel #28
0
func EncryptPrefixNonce(plaintxt []byte, nonce *[24]byte, secret *[32]byte) []byte {
	buf := make([]byte, 24, 24+len(plaintxt)+secretbox.Overhead)
	copy(buf, nonce[:])
	// Seal *appends* to buf
	return secretbox.Seal(buf, plaintxt, nonce, secret)
}
Beispiel #29
0
func main() {
	runtime.GOMAXPROCS(2)
	flag.Parse()

	if len(*secret) == 0 {
		fmt.Fprintf(os.Stderr, "The shared secret must be given as --secret\n")
		os.Exit(2)
	}
	if len(*keyFile) == 0 {
		fmt.Fprintf(os.Stderr, "The path to a find containing the public key material to exchange must be given as --key-file\n")
		os.Exit(2)
	}

	pubKeyBytes, err := ioutil.ReadFile(*keyFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to read key file: %s\n", err)
		os.Exit(2)
	}

	const maxBody = 4096
	if limit := maxBody - 24 - secretbox.Overhead; len(pubKeyBytes) > limit {
		fmt.Fprintf(os.Stderr, "--key-file is too large (%d bytes of a maximum of %d)\n", len(pubKeyBytes), limit)
		os.Exit(2)
	}

	// Run scrypt on a goroutine so that we can overlap it with the network
	// delay.
	keyChan := make(chan []byte)
	go deriveKey(keyChan, *secret)

	var dialer proxy.Dialer
	dialer = proxy.Direct
	if len(*torProxy) > 0 {
		fmt.Fprintf(os.Stderr, "Using SOCKS5 proxy at %s\n", *torProxy)
		dialer, err = proxy.SOCKS5("tcp", *torProxy, nil, dialer)
		if err != nil {
			panic(err)
		}
	}

	fmt.Fprintf(os.Stderr, "Starting TCP connection to %s\n", *server)
	rawConn, err := dialer.Dial("tcp", *server)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to connect to server: %s\n", err)
		os.Exit(2)
	}

	var conn net.Conn
	if *useTLS {
		hostname, _, err := net.SplitHostPort(*server)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to split %s into host and post: %s\n", *server, err)
			os.Exit(2)
		}
		tlsConn := tls.Client(rawConn, &tls.Config{
			ServerName: hostname,
		})
		fmt.Fprintf(os.Stderr, "Starting TLS handshake\n")
		if err := tlsConn.Handshake(); err != nil {
			rawConn.Close()
			fmt.Fprintf(os.Stderr, "TLS handshake failed: %s\n", err)
			os.Exit(2)
		}
		conn = tlsConn
	} else {
		conn = rawConn
	}
	defer conn.Close()

	var keySlice []byte
	select {
	case keySlice = <-keyChan:
	default:
		fmt.Fprintf(os.Stderr, "Waiting for key derivation to complete. This may take some time.\n")
		keySlice = <-keyChan
	}
	var key [32]byte
	copy(key[:], keySlice)

	mac := hmac.New(sha256.New, key[:])
	mac.Write(pubKeyBytes)
	nonceSlice := mac.Sum(nil)
	var nonce [24]byte
	copy(nonce[:], nonceSlice)

	box := make([]byte, len(nonce)+secretbox.Overhead+len(pubKeyBytes))
	copy(box, nonce[:])
	secretbox.Seal(box[len(nonce):len(nonce)], pubKeyBytes, &nonce, &key)

	h := sha256.New()
	h.Write(key[:])
	tag := h.Sum(nil)

	body := bytes.NewReader(box)
	request, err := http.NewRequest("POST", "http://"+*server+"/exchange/"+hex.EncodeToString(tag), body)
	if err != nil {
		panic(err)
	}
	request.ContentLength = int64(len(box))
	request.Header.Add("Content-Type", "application/octet-stream")

	request.Write(conn)
	fmt.Fprintf(os.Stderr, "Request sent. Waiting for HTTP reply\n")
	replyReader := bufio.NewReader(conn)

	response, err := http.ReadResponse(replyReader, request)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error reading reply from server: %s\n", err)
		os.Exit(2)
	}

	switch response.StatusCode {
	case 409:
		fmt.Fprintf(os.Stderr, "The transaction failed because this key has been used recently by two other parties.\n")
		os.Exit(2)
	case 204:
		fmt.Fprintf(os.Stderr, "Material submitted, but the other party has yet to start the process. Try again later with the same arguments.\n")
		os.Exit(1)
	case 200:
		r := &io.LimitedReader{R: response.Body, N: maxBody + 1}
		body, err := ioutil.ReadAll(r)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error reading from server: %s\n", err)
			os.Exit(2)
		}
		if len(body) > maxBody {
			fmt.Fprintf(os.Stderr, "Reply from server is too large\n")
			os.Exit(2)
		}
		if len(body) < len(nonce)+secretbox.Overhead {
			fmt.Fprintf(os.Stderr, "Reply from server is too short to be valid: %x\n", body)
			os.Exit(2)
		}
		copy(nonce[:], body)
		unsealed, ok := secretbox.Open(nil, body[len(nonce):], &nonce, &key)
		if !ok {
			fmt.Fprintf(os.Stderr, "Failed to authenticate reply from server\n")
			os.Exit(2)
		}
		os.Stdout.Write(unsealed)
	default:
		fmt.Fprintf(os.Stderr, "HTTP error from server: %s\n", response.Status)
		io.Copy(os.Stderr, response.Body)
		os.Exit(2)
	}
}