// 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) }
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) }
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 }
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(";") }
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) }
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 }
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 }
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 }
// 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 }
// 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 }
// 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 }
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() } }
// 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) }
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 }
// 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 }
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: "/"} }
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 }
// 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 }
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 }
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 }
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 }
// 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) }
// 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) }
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 }
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[:]) } } } } }
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) } } }
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() } }
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) }
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) } }